1
2 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
3 * vim: set ts=8 sts=2 et sw=2 tw=80:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 /*
9 * GC-internal definition of GC cell kinds.
10 */
11
12 #ifndef gc_AllocKind_h
13 #define gc_AllocKind_h
14
15 #include "mozilla/EnumeratedArray.h"
16 #include "mozilla/EnumeratedRange.h"
17
18 #include <iterator>
19 #include <stdint.h>
20
21 #include "js/TraceKind.h"
22 #include "js/Utility.h"
23
24 class JSDependentString;
25 class JSExternalString;
26 class JSFatInlineString;
27 class JSLinearString;
28 class JSRope;
29 class JSThinInlineString;
30
31 namespace js {
32
33 class CompactPropMap;
34 class FatInlineAtom;
35 class NormalAtom;
36 class NormalPropMap;
37 class DictionaryPropMap;
38
39 namespace gc {
40
41 // The GC allocation kinds.
42 //
43 // These are defined by macros which enumerate the different allocation kinds
44 // and supply the following information:
45 //
46 // - the corresponding AllocKind
47 // - their JS::TraceKind
48 // - their C++ base type
49 // - a C++ type of the correct size
50 // - whether they can be finalized on the background thread
51 // - whether they can be allocated in the nursery
52 // - whether they can be compacted
53
54 // clang-format off
55 #define FOR_EACH_OBJECT_ALLOCKIND(D) \
56 /* AllocKind TraceKind TypeName SizedType BGFinal Nursery Compact */ \
57 D(FUNCTION, Object, JSObject, JSObject_Slots4, true, true, true) \
58 D(FUNCTION_EXTENDED, Object, JSObject, JSObject_Slots6, true, true, true) \
59 D(OBJECT0, Object, JSObject, JSObject_Slots0, false, false, true) \
60 D(OBJECT0_BACKGROUND, Object, JSObject, JSObject_Slots0, true, true, true) \
61 D(OBJECT2, Object, JSObject, JSObject_Slots2, false, false, true) \
62 D(OBJECT2_BACKGROUND, Object, JSObject, JSObject_Slots2, true, true, true) \
63 D(ARRAYBUFFER4, Object, JSObject, JSObject_Slots4, true, true, true) \
64 D(OBJECT4, Object, JSObject, JSObject_Slots4, false, false, true) \
65 D(OBJECT4_BACKGROUND, Object, JSObject, JSObject_Slots4, true, true, true) \
66 D(ARRAYBUFFER8, Object, JSObject, JSObject_Slots8, true, true, true) \
67 D(OBJECT8, Object, JSObject, JSObject_Slots8, false, false, true) \
68 D(OBJECT8_BACKGROUND, Object, JSObject, JSObject_Slots8, true, true, true) \
69 D(ARRAYBUFFER12, Object, JSObject, JSObject_Slots12, true, true, true) \
70 D(OBJECT12, Object, JSObject, JSObject_Slots12, false, false, true) \
71 D(OBJECT12_BACKGROUND, Object, JSObject, JSObject_Slots12, true, true, true) \
72 D(ARRAYBUFFER16, Object, JSObject, JSObject_Slots16, true, true, true) \
73 D(OBJECT16, Object, JSObject, JSObject_Slots16, false, false, true) \
74 D(OBJECT16_BACKGROUND, Object, JSObject, JSObject_Slots16, true, true, true)
75
76 #define FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \
77 /* AllocKind TraceKind TypeName SizedType BGFinal Nursery Compact */ \
78 D(SCRIPT, Script, js::BaseScript, js::BaseScript, false, false, true) \
79 D(SHAPE, Shape, js::Shape, js::Shape, true, false, true) \
80 D(BASE_SHAPE, BaseShape, js::BaseShape, js::BaseShape, true, false, true) \
81 D(GETTER_SETTER, GetterSetter, js::GetterSetter, js::GetterSetter, true, false, true) \
82 D(COMPACT_PROP_MAP, PropMap, js::CompactPropMap, js::CompactPropMap, true, false, true) \
83 D(NORMAL_PROP_MAP, PropMap, js::NormalPropMap, js::NormalPropMap, true, false, true) \
84 D(DICT_PROP_MAP, PropMap, js::DictionaryPropMap, js::DictionaryPropMap, true, false, true) \
85 D(EXTERNAL_STRING, String, JSExternalString, JSExternalString, true, false, true) \
86 D(FAT_INLINE_ATOM, String, js::FatInlineAtom, js::FatInlineAtom, true, false, false) \
87 D(ATOM, String, js::NormalAtom, js::NormalAtom, true, false, false) \
88 D(SYMBOL, Symbol, JS::Symbol, JS::Symbol, true, false, false) \
89 D(JITCODE, JitCode, js::jit::JitCode, js::jit::JitCode, false, false, false) \
90 D(SCOPE, Scope, js::Scope, js::Scope, true, false, true) \
91 D(REGEXP_SHARED, RegExpShared, js::RegExpShared, js::RegExpShared, true, false, true)
92
93 #define FOR_EACH_NONOBJECT_NURSERY_ALLOCKIND(D) \
94 /* AllocKind TraceKind TypeName SizedType BGFinal Nursery Compact */ \
95 D(BIGINT, BigInt, JS::BigInt, JS::BigInt, true, true, true)
96
97 #define FOR_EACH_NURSERY_STRING_ALLOCKIND(D) \
98 D(FAT_INLINE_STRING, String, JSFatInlineString, JSFatInlineString, true, true, true) \
99 D(STRING, String, JSString, JSString, true, true, true)
100 // clang-format on
101
102 #define FOR_EACH_NONOBJECT_ALLOCKIND(D) \
103 FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \
104 FOR_EACH_NONOBJECT_NURSERY_ALLOCKIND(D) \
105 FOR_EACH_NURSERY_STRING_ALLOCKIND(D)
106
107 #define FOR_EACH_ALLOCKIND(D) \
108 FOR_EACH_OBJECT_ALLOCKIND(D) \
109 FOR_EACH_NONOBJECT_ALLOCKIND(D)
110
111 #define DEFINE_ALLOC_KIND(allocKind, _1, _2, _3, _4, _5, _6) allocKind,
112 enum class AllocKind : uint8_t {
113 // clang-format off
114 FOR_EACH_OBJECT_ALLOCKIND(DEFINE_ALLOC_KIND)
115
116 OBJECT_LIMIT,
117 OBJECT_LAST = OBJECT_LIMIT - 1,
118
119 FOR_EACH_NONOBJECT_ALLOCKIND(DEFINE_ALLOC_KIND)
120
121 LIMIT,
122 LAST = LIMIT - 1,
123
124 FIRST = 0,
125 OBJECT_FIRST = FUNCTION // Hardcoded to first object kind.
126 // clang-format on
127 };
128 #undef DEFINE_ALLOC_KIND
129
130 static_assert(int(AllocKind::FIRST) == 0,
131 "Various places depend on AllocKind starting at 0");
132 static_assert(int(AllocKind::OBJECT_FIRST) == 0,
133 "OBJECT_FIRST must be defined as the first object kind");
134
135 constexpr size_t AllocKindCount = size_t(AllocKind::LIMIT);
136
137 /*
138 * This flag allows an allocation site to request a specific heap based upon the
139 * estimated lifetime or lifetime requirements of objects allocated from that
140 * site.
141 */
142 enum InitialHeap : uint8_t { DefaultHeap, TenuredHeap };
143
IsAllocKind(AllocKind kind)144 inline bool IsAllocKind(AllocKind kind) {
145 return kind >= AllocKind::FIRST && kind <= AllocKind::LIMIT;
146 }
147
IsValidAllocKind(AllocKind kind)148 inline bool IsValidAllocKind(AllocKind kind) {
149 return kind >= AllocKind::FIRST && kind <= AllocKind::LAST;
150 }
151
152 const char* AllocKindName(AllocKind kind);
153
IsObjectAllocKind(AllocKind kind)154 inline bool IsObjectAllocKind(AllocKind kind) {
155 return kind >= AllocKind::OBJECT_FIRST && kind <= AllocKind::OBJECT_LAST;
156 }
157
IsShapeAllocKind(AllocKind kind)158 inline bool IsShapeAllocKind(AllocKind kind) {
159 return kind == AllocKind::SHAPE;
160 }
161
162 // Returns a sequence for use in a range-based for loop,
163 // to iterate over all alloc kinds.
AllAllocKinds()164 inline auto AllAllocKinds() {
165 return mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT);
166 }
167
168 // Returns a sequence for use in a range-based for loop,
169 // to iterate over all object alloc kinds.
ObjectAllocKinds()170 inline auto ObjectAllocKinds() {
171 return mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST,
172 AllocKind::OBJECT_LIMIT);
173 }
174
175 // Returns a sequence for use in a range-based for loop,
176 // to iterate over alloc kinds from |first| to |limit|, exclusive.
177 inline auto SomeAllocKinds(AllocKind first = AllocKind::FIRST,
178 AllocKind limit = AllocKind::LIMIT) {
179 MOZ_ASSERT(IsAllocKind(first), "|first| is not a valid AllocKind!");
180 MOZ_ASSERT(IsAllocKind(limit), "|limit| is not a valid AllocKind!");
181 return mozilla::MakeEnumeratedRange(first, limit);
182 }
183
184 // AllAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
185 // with each index corresponding to a particular alloc kind.
186 template <typename ValueType>
187 using AllAllocKindArray =
188 mozilla::EnumeratedArray<AllocKind, AllocKind::LIMIT, ValueType>;
189
190 // ObjectAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
191 // with each index corresponding to a particular object alloc kind.
192 template <typename ValueType>
193 using ObjectAllocKindArray =
194 mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;
195
196 /*
197 * Map from C++ type to alloc kind for non-object types. JSObject does not have
198 * a 1:1 mapping, so must use Arena::thingSize.
199 *
200 * The AllocKind is available as MapTypeToAllocKind<SomeType>::kind.
201 *
202 * There are specializations for strings since more than one derived string type
203 * shares the same alloc kind.
204 */
205 template <typename T>
206 struct MapTypeToAllocKind {};
207 #define EXPAND_MAPTYPETOALLOCKIND(allocKind, traceKind, type, sizedType, \
208 bgFinal, nursery, compact) \
209 template <> \
210 struct MapTypeToAllocKind<type> { \
211 static const AllocKind kind = AllocKind::allocKind; \
212 };
213 FOR_EACH_NONOBJECT_ALLOCKIND(EXPAND_MAPTYPETOALLOCKIND)
214 #undef EXPAND_MAPTYPETOALLOCKIND
215
216 template <>
217 struct MapTypeToAllocKind<JSDependentString> {
218 static const AllocKind kind = AllocKind::STRING;
219 };
220 template <>
221 struct MapTypeToAllocKind<JSRope> {
222 static const AllocKind kind = AllocKind::STRING;
223 };
224 template <>
225 struct MapTypeToAllocKind<JSLinearString> {
226 static const AllocKind kind = AllocKind::STRING;
227 };
228 template <>
229 struct MapTypeToAllocKind<JSThinInlineString> {
230 static const AllocKind kind = AllocKind::STRING;
231 };
232
233 static inline JS::TraceKind MapAllocToTraceKind(AllocKind kind) {
234 static const JS::TraceKind map[] = {
235 #define EXPAND_ELEMENT(allocKind, traceKind, type, sizedType, bgFinal, \
236 nursery, compact) \
237 JS::TraceKind::traceKind,
238 FOR_EACH_ALLOCKIND(EXPAND_ELEMENT)
239 #undef EXPAND_ELEMENT
240 };
241
242 static_assert(std::size(map) == AllocKindCount,
243 "AllocKind-to-TraceKind mapping must be in sync");
244 return map[size_t(kind)];
245 }
246
247 static inline bool IsNurseryAllocable(AllocKind kind) {
248 MOZ_ASSERT(IsValidAllocKind(kind));
249
250 static const bool map[] = {
251 #define DEFINE_NURSERY_ALLOCABLE(_1, _2, _3, _4, _5, nursery, _6) nursery,
252 FOR_EACH_ALLOCKIND(DEFINE_NURSERY_ALLOCABLE)
253 #undef DEFINE_NURSERY_ALLOCABLE
254 };
255
256 static_assert(std::size(map) == AllocKindCount,
257 "IsNurseryAllocable sanity check");
258 return map[size_t(kind)];
259 }
260
261 static inline bool IsBackgroundFinalized(AllocKind kind) {
262 MOZ_ASSERT(IsValidAllocKind(kind));
263
264 static const bool map[] = {
265 #define DEFINE_BACKGROUND_FINALIZED(_1, _2, _3, _4, bgFinal, _5, _6) bgFinal,
266 FOR_EACH_ALLOCKIND(DEFINE_BACKGROUND_FINALIZED)
267 #undef DEFINE_BACKGROUND_FINALIZED
268 };
269
270 static_assert(std::size(map) == AllocKindCount,
271 "IsBackgroundFinalized sanity check");
272 return map[size_t(kind)];
273 }
274
275 static inline bool IsForegroundFinalized(AllocKind kind) {
276 return !IsBackgroundFinalized(kind);
277 }
278
279 static inline bool IsCompactingKind(AllocKind kind) {
280 MOZ_ASSERT(IsValidAllocKind(kind));
281
282 static const bool map[] = {
283 #define DEFINE_COMPACTING_KIND(_1, _2, _3, _4, _5, _6, compact) compact,
284 FOR_EACH_ALLOCKIND(DEFINE_COMPACTING_KIND)
285 #undef DEFINE_COMPACTING_KIND
286 };
287
288 static_assert(std::size(map) == AllocKindCount,
289 "IsCompactingKind sanity check");
290 return map[size_t(kind)];
291 }
292
293 static inline bool IsMovableKind(AllocKind kind) {
294 return IsNurseryAllocable(kind) || IsCompactingKind(kind);
295 }
296
297 } /* namespace gc */
298 } /* namespace js */
299
300 #endif /* gc_AllocKind_h */
301