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