AllocKind.h (15337B)
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 /* 8 * GC-internal definition of GC cell kinds. 9 */ 10 11 #ifndef gc_AllocKind_h 12 #define gc_AllocKind_h 13 14 #include "mozilla/EnumeratedArray.h" 15 #include "mozilla/EnumeratedRange.h" 16 17 #include <stdint.h> 18 19 #include "js/TraceKind.h" 20 21 class JSDependentString; 22 class JSExternalString; 23 class JSFatInlineString; 24 class JSLinearString; 25 class JSRope; 26 class JSThinInlineString; 27 28 namespace js { 29 30 class CompactPropMap; 31 class FatInlineAtom; 32 class ThinInlineAtom; 33 class NormalAtom; 34 class NormalPropMap; 35 class DictionaryPropMap; 36 class DictionaryShape; 37 class SharedShape; 38 class ProxyShape; 39 class WasmGCShape; 40 41 namespace gc { 42 43 // The GC allocation kinds. 44 // 45 // These are defined by macros which enumerate the different allocation kinds 46 // and supply the following information: 47 // 48 // - the corresponding AllocKind 49 // - their JS::TraceKind 50 // - their C++ base type 51 // - a C++ type of the correct size 52 // - their FinalizeKind (see above) 53 // - whether they can be allocated in the nursery (this is true for foreground 54 // finalized objects but these will can only actually be allocated in the 55 // nursery if JSCLASS_SKIP_NURSERY_FINALIZE is set) 56 // - whether they can be compacted 57 58 // clang-format off 59 #define FOR_EACH_OBJECT_ALLOCKIND(D) \ 60 /* AllocKind TraceKind TypeName SizedType Finalize Nursery Compact */ \ 61 D(FUNCTION, Object, JSObject, JSObject_Slots4, None, true, true) \ 62 D(FUNCTION_EXTENDED, Object, JSObject, JSObject_Slots7, None, true, true) \ 63 D(OBJECT0, Object, JSObject, JSObject_Slots0, None, true, true) \ 64 D(OBJECT0_FOREGROUND, Object, JSObject, JSObject_Slots0, Foreground, true, true) \ 65 D(OBJECT0_BACKGROUND, Object, JSObject, JSObject_Slots0, Background, true, true) \ 66 D(OBJECT2, Object, JSObject, JSObject_Slots2, None, true, true) \ 67 D(OBJECT2_FOREGROUND, Object, JSObject, JSObject_Slots2, Foreground, true, true) \ 68 D(OBJECT2_BACKGROUND, Object, JSObject, JSObject_Slots2, Background, true, true) \ 69 D(ARRAYBUFFER4, Object, JSObject, JSObject_Slots4, Background, true, true) \ 70 D(OBJECT4, Object, JSObject, JSObject_Slots4, None, true, true) \ 71 D(OBJECT4_FOREGROUND, Object, JSObject, JSObject_Slots4, Foreground, true, true) \ 72 D(OBJECT4_BACKGROUND, Object, JSObject, JSObject_Slots4, Background, true, true) \ 73 D(ARRAYBUFFER6, Object, JSObject, JSObject_Slots6, Background, true, true) \ 74 D(OBJECT6, Object, JSObject, JSObject_Slots6, None, true, true) \ 75 D(OBJECT6_FOREGROUND, Object, JSObject, JSObject_Slots6, Foreground, true, true) \ 76 D(OBJECT6_BACKGROUND, Object, JSObject, JSObject_Slots6, Background, true, true) \ 77 D(ARRAYBUFFER8, Object, JSObject, JSObject_Slots8, Background, true, true) \ 78 D(OBJECT8, Object, JSObject, JSObject_Slots8, None, true, true) \ 79 D(OBJECT8_FOREGROUND, Object, JSObject, JSObject_Slots8, Foreground, true, true) \ 80 D(OBJECT8_BACKGROUND, Object, JSObject, JSObject_Slots8, Background, true, true) \ 81 D(ARRAYBUFFER12, Object, JSObject, JSObject_Slots12, Background, true, true) \ 82 D(OBJECT12, Object, JSObject, JSObject_Slots12, None, true, true) \ 83 D(OBJECT12_FOREGROUND, Object, JSObject, JSObject_Slots12, Foreground, true, true) \ 84 D(OBJECT12_BACKGROUND, Object, JSObject, JSObject_Slots12, Background, true, true) \ 85 D(ARRAYBUFFER16, Object, JSObject, JSObject_Slots16, Background, true, true) \ 86 D(OBJECT16, Object, JSObject, JSObject_Slots16, None, true, true) \ 87 D(OBJECT16_FOREGROUND, Object, JSObject, JSObject_Slots16, Foreground, true, true) \ 88 D(OBJECT16_BACKGROUND, Object, JSObject, JSObject_Slots16, Background, true, true) 89 90 #define FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \ 91 /* AllocKind TraceKind TypeName SizedType Finalize Nursery Compact */ \ 92 D(SCRIPT, Script, js::BaseScript, js::BaseScript, Foreground, false, true) \ 93 D(SHAPE, Shape, js::Shape, js::SizedShape, Background, false, true) \ 94 D(BASE_SHAPE, BaseShape, js::BaseShape, js::BaseShape, None, false, true) \ 95 D(GETTER_SETTER, GetterSetter, js::GetterSetter, js::GetterSetter, None, true, true) \ 96 D(COMPACT_PROP_MAP, PropMap, js::CompactPropMap, js::CompactPropMap, Background, false, true) \ 97 D(NORMAL_PROP_MAP, PropMap, js::NormalPropMap, js::NormalPropMap, Background, false, true) \ 98 D(DICT_PROP_MAP, PropMap, js::DictionaryPropMap, js::DictionaryPropMap, Background, false, true) \ 99 D(EXTERNAL_STRING, String, JSExternalString, JSExternalString, Background, false, true) \ 100 D(FAT_INLINE_ATOM, String, js::FatInlineAtom, js::FatInlineAtom, None, false, false) \ 101 D(ATOM, String, js::NormalAtom, js::NormalAtom, Background, false, false) \ 102 D(SYMBOL, Symbol, JS::Symbol, JS::Symbol, None, false, false) \ 103 D(JITCODE, JitCode, js::jit::JitCode, js::jit::JitCode, Foreground, false, false) \ 104 D(SCOPE, Scope, js::Scope, js::Scope, None, false, true) \ 105 D(REGEXP_SHARED, RegExpShared, js::RegExpShared, js::RegExpShared, Background, false, true) 106 107 #define FOR_EACH_NONOBJECT_NURSERY_ALLOCKIND(D) \ 108 /* AllocKind TraceKind TypeName SizedType Finalize Nursery Compact */ \ 109 D(BIGINT, BigInt, JS::BigInt, JS::BigInt, None, true, true) 110 111 #define FOR_EACH_NURSERY_STRING_ALLOCKIND(D) \ 112 /* AllocKind TraceKind TypeName SizedType Finalize Nursery Compact */ \ 113 D(FAT_INLINE_STRING, String, JSFatInlineString, JSFatInlineString, None, true, true) \ 114 D(STRING, String, JSString, JSString, Background, true, true) 115 116 #define FOR_EACH_NONOBJECT_NONBUFFER_ALLOCKIND(D) \ 117 FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \ 118 FOR_EACH_NONOBJECT_NURSERY_ALLOCKIND(D) \ 119 FOR_EACH_NURSERY_STRING_ALLOCKIND(D) 120 121 #define FOR_EACH_ALLOCKIND(D) \ 122 FOR_EACH_OBJECT_ALLOCKIND(D) \ 123 FOR_EACH_NONOBJECT_NONBUFFER_ALLOCKIND(D) 124 125 #define DEFINE_ALLOC_KIND(allocKind, _1, _2, _3, _4, _5, _6) allocKind, 126 enum class AllocKind : uint8_t { 127 // clang-format off 128 FOR_EACH_OBJECT_ALLOCKIND(DEFINE_ALLOC_KIND) 129 130 OBJECT_LIMIT, 131 OBJECT_LAST = OBJECT_LIMIT - 1, 132 133 FOR_EACH_NONOBJECT_NONBUFFER_ALLOCKIND(DEFINE_ALLOC_KIND) 134 135 LIMIT, 136 LAST = LIMIT - 1, 137 138 INVALID = LIMIT, 139 140 FIRST = 0, 141 OBJECT_FIRST = FUNCTION, // Hardcoded to first object kind. 142 // clang-format on 143 }; 144 #undef DEFINE_ALLOC_KIND 145 146 static_assert(int(AllocKind::FIRST) == 0, 147 "Various places depend on AllocKind starting at 0"); 148 static_assert(int(AllocKind::OBJECT_FIRST) == 0, 149 "OBJECT_FIRST must be defined as the first object kind"); 150 151 constexpr size_t AllocKindCount = size_t(AllocKind::LIMIT); 152 153 /* 154 * A flag specifying either the tenured heap or a default heap (which may be 155 * either the nursery or the tenured heap). 156 * 157 * This allows an allocation site to request a heap based upon the estimated 158 * lifetime or lifetime requirements of objects allocated from that site. 159 * 160 * Order is important as these are numerically compared. 161 */ 162 enum class Heap : uint8_t { Default = 0, Tenured = 1 }; 163 164 enum class FinalizeKind { 165 // Cells are not finalized. Arenas containing these cells are swept on a 166 // background thread. 167 None = 0, 168 169 // Requires foreground finalization. May have client-supplied finalizer. 170 Foreground, 171 172 // Does not require foreground finalization but is non-trivial. May have 173 // client-supplied finalizer. Finalized on a background thread. 174 Background 175 }; 176 177 constexpr bool IsAllocKind(AllocKind kind) { 178 return kind >= AllocKind::FIRST && kind <= AllocKind::LIMIT; 179 } 180 181 constexpr bool IsValidAllocKind(AllocKind kind) { 182 return kind >= AllocKind::FIRST && kind <= AllocKind::LAST; 183 } 184 185 const char* AllocKindName(AllocKind kind); 186 187 constexpr bool IsObjectAllocKind(AllocKind kind) { 188 return kind >= AllocKind::OBJECT_FIRST && kind <= AllocKind::OBJECT_LAST; 189 } 190 191 constexpr bool IsShapeAllocKind(AllocKind kind) { 192 return kind == AllocKind::SHAPE; 193 } 194 195 // Returns a sequence for use in a range-based for loop, 196 // to iterate over all alloc kinds. 197 constexpr auto AllAllocKinds() { 198 return mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT); 199 } 200 201 // Returns a sequence for use in a range-based for loop, 202 // to iterate over all object alloc kinds. 203 constexpr auto ObjectAllocKinds() { 204 return mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST, 205 AllocKind::OBJECT_LIMIT); 206 } 207 208 // Returns a sequence for use in a range-based for loop, 209 // to iterate over alloc kinds from |first| to |limit|, exclusive. 210 constexpr auto SomeAllocKinds(AllocKind first = AllocKind::FIRST, 211 AllocKind limit = AllocKind::LIMIT) { 212 MOZ_ASSERT(IsAllocKind(first), "|first| is not a valid AllocKind!"); 213 MOZ_ASSERT(IsAllocKind(limit), "|limit| is not a valid AllocKind!"); 214 return mozilla::MakeEnumeratedRange(first, limit); 215 } 216 217 // AllAllocKindArray<ValueType> gives an enumerated array of ValueTypes, 218 // with each index corresponding to a particular alloc kind. 219 template <typename ValueType> 220 using AllAllocKindArray = 221 mozilla::EnumeratedArray<AllocKind, ValueType, size_t(AllocKind::LIMIT)>; 222 223 // ObjectAllocKindArray<ValueType> gives an enumerated array of ValueTypes, 224 // with each index corresponding to a particular object alloc kind. 225 template <typename ValueType> 226 using ObjectAllocKindArray = 227 mozilla::EnumeratedArray<AllocKind, ValueType, 228 size_t(AllocKind::OBJECT_LIMIT)>; 229 230 /* 231 * Map from C++ type to alloc kind for non-object types. JSObject does not have 232 * a 1:1 mapping, so must use Arena::thingSize. 233 * 234 * The AllocKind is available as MapTypeToAllocKind<SomeType>::kind. 235 * 236 * There are specializations for strings and shapes since more than one derived 237 * type shares the same alloc kind. 238 */ 239 template <typename T> 240 struct MapTypeToAllocKind {}; 241 #define EXPAND_MAPTYPETOALLOCKIND(allocKind, _1, type, _2, _3, _4, _5) \ 242 template <> \ 243 struct MapTypeToAllocKind<type> { \ 244 static const AllocKind kind = AllocKind::allocKind; \ 245 }; 246 FOR_EACH_NONOBJECT_NONBUFFER_ALLOCKIND(EXPAND_MAPTYPETOALLOCKIND) 247 #undef EXPAND_MAPTYPETOALLOCKIND 248 249 template <> 250 struct MapTypeToAllocKind<JSDependentString> { 251 static const AllocKind kind = AllocKind::STRING; 252 }; 253 template <> 254 struct MapTypeToAllocKind<JSRope> { 255 static const AllocKind kind = AllocKind::STRING; 256 }; 257 template <> 258 struct MapTypeToAllocKind<JSLinearString> { 259 static const AllocKind kind = AllocKind::STRING; 260 }; 261 template <> 262 struct MapTypeToAllocKind<JSThinInlineString> { 263 static const AllocKind kind = AllocKind::STRING; 264 }; 265 template <> 266 struct MapTypeToAllocKind<js::ThinInlineAtom> { 267 static const AllocKind kind = AllocKind::ATOM; 268 }; 269 270 template <> 271 struct MapTypeToAllocKind<js::SharedShape> { 272 static const AllocKind kind = AllocKind::SHAPE; 273 }; 274 template <> 275 struct MapTypeToAllocKind<js::DictionaryShape> { 276 static const AllocKind kind = AllocKind::SHAPE; 277 }; 278 template <> 279 struct MapTypeToAllocKind<js::ProxyShape> { 280 static const AllocKind kind = AllocKind::SHAPE; 281 }; 282 template <> 283 struct MapTypeToAllocKind<js::WasmGCShape> { 284 static const AllocKind kind = AllocKind::SHAPE; 285 }; 286 287 constexpr JS::TraceKind MapAllocToTraceKind(AllocKind kind) { 288 constexpr JS::TraceKind map[] = { 289 #define EXPAND_ELEMENT(_1, traceKind, _2, _3, _4, _5, _6) \ 290 JS::TraceKind::traceKind, 291 FOR_EACH_ALLOCKIND(EXPAND_ELEMENT) 292 #undef EXPAND_ELEMENT 293 }; 294 295 static_assert(std::size(map) == AllocKindCount, 296 "AllocKind-to-TraceKind mapping must be in sync"); 297 return map[size_t(kind)]; 298 } 299 300 constexpr bool IsNurseryAllocable(AllocKind kind) { 301 MOZ_ASSERT(IsValidAllocKind(kind)); 302 303 constexpr bool map[] = { 304 #define DEFINE_NURSERY_ALLOCABLE(_1, _2, _3, _4, _5, nursery, _6) nursery, 305 FOR_EACH_ALLOCKIND(DEFINE_NURSERY_ALLOCABLE) 306 #undef DEFINE_NURSERY_ALLOCABLE 307 }; 308 309 static_assert(std::size(map) == AllocKindCount, 310 "IsNurseryAllocable sanity check"); 311 return map[size_t(kind)]; 312 } 313 314 constexpr FinalizeKind GetFinalizeKind(AllocKind kind) { 315 MOZ_ASSERT(IsValidAllocKind(kind)); 316 317 constexpr FinalizeKind map[] = { 318 #define DEFINE_FINALIZE_KIND(_1, _2, _3, _4, finalizeKind, _5, _6) \ 319 FinalizeKind::finalizeKind, 320 FOR_EACH_ALLOCKIND(DEFINE_FINALIZE_KIND) 321 #undef DEFINE_FINALIZE_KIND 322 }; 323 324 static_assert(std::size(map) == AllocKindCount); 325 return map[size_t(kind)]; 326 } 327 328 constexpr bool IsFinalizedKind(AllocKind kind) { 329 return GetFinalizeKind(kind) != FinalizeKind::None; 330 } 331 332 constexpr bool IsForegroundFinalized(AllocKind kind) { 333 return GetFinalizeKind(kind) == FinalizeKind::Foreground; 334 } 335 336 constexpr bool IsBackgroundFinalized(AllocKind kind) { 337 return GetFinalizeKind(kind) == FinalizeKind::Background; 338 } 339 340 // Arenas containing cells of kind FinalizeKind::None and 341 // FinalizeKind::Background are swept on a background thread. 342 constexpr bool IsBackgroundSwept(AllocKind kind) { 343 return !IsForegroundFinalized(kind); 344 } 345 346 constexpr bool IsCompactingKind(AllocKind kind) { 347 MOZ_ASSERT(IsValidAllocKind(kind)); 348 349 constexpr bool map[] = { 350 #define DEFINE_COMPACTING_KIND(_1, _2, _3, _4, _5, _6, compact) compact, 351 FOR_EACH_ALLOCKIND(DEFINE_COMPACTING_KIND) 352 #undef DEFINE_COMPACTING_KIND 353 }; 354 355 static_assert(std::size(map) == AllocKindCount, 356 "IsCompactingKind sanity check"); 357 return map[size_t(kind)]; 358 } 359 360 constexpr bool IsMovableKind(AllocKind kind) { 361 return IsNurseryAllocable(kind) || IsCompactingKind(kind); 362 } 363 364 } /* namespace gc */ 365 } /* namespace js */ 366 367 #endif /* gc_AllocKind_h */