summaryrefslogtreecommitdiffstats
path: root/js/src/gc/AllocKind.h
blob: 89ae7cc4fee504171969ee0fd9f9900d2d38b003 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 * vim: set ts=8 sts=2 et sw=2 tw=80:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * GC-internal definition of GC cell kinds.
 */

#ifndef gc_AllocKind_h
#define gc_AllocKind_h

#include "mozilla/EnumeratedArray.h"
#include "mozilla/EnumeratedRange.h"

#include <iterator>
#include <stdint.h>

#include "js/TraceKind.h"
#include "js/Utility.h"

namespace js {
namespace gc {

// The GC allocation kinds.
//
// These are defined by macros which enumerate the different allocation kinds
// and supply the following information:
//
//  - the corresponding AllocKind
//  - their JS::TraceKind
//  - their C++ base type
//  - a C++ type of the correct size
//  - whether they can be finalized on the background thread
//  - whether they can be allocated in the nursery
//  - whether they can be compacted

// clang-format off
#define FOR_EACH_OBJECT_ALLOCKIND(D) \
 /* AllocKind              TraceKind     TypeName           SizedType          BGFinal Nursery Compact */ \
    D(FUNCTION,            Object,       JSObject,          JSFunction,        true,   true,   true) \
    D(FUNCTION_EXTENDED,   Object,       JSObject,          FunctionExtended,  true,   true,   true) \
    D(OBJECT0,             Object,       JSObject,          JSObject_Slots0,   false,  false,  true) \
    D(OBJECT0_BACKGROUND,  Object,       JSObject,          JSObject_Slots0,   true,   true,   true) \
    D(OBJECT2,             Object,       JSObject,          JSObject_Slots2,   false,  false,  true) \
    D(OBJECT2_BACKGROUND,  Object,       JSObject,          JSObject_Slots2,   true,   true,   true) \
    D(ARRAYBUFFER4,        Object,       JSObject,          JSObject_Slots4,   true,   true,   true) \
    D(OBJECT4,             Object,       JSObject,          JSObject_Slots4,   false,  false,  true) \
    D(OBJECT4_BACKGROUND,  Object,       JSObject,          JSObject_Slots4,   true,   true,   true) \
    D(ARRAYBUFFER8,        Object,       JSObject,          JSObject_Slots8,   true,   true,   true) \
    D(OBJECT8,             Object,       JSObject,          JSObject_Slots8,   false,  false,  true) \
    D(OBJECT8_BACKGROUND,  Object,       JSObject,          JSObject_Slots8,   true,   true,   true) \
    D(ARRAYBUFFER12,       Object,       JSObject,          JSObject_Slots12,  true,   true,   true) \
    D(OBJECT12,            Object,       JSObject,          JSObject_Slots12,  false,  false,  true) \
    D(OBJECT12_BACKGROUND, Object,       JSObject,          JSObject_Slots12,  true,   true,   true) \
    D(ARRAYBUFFER16,       Object,       JSObject,          JSObject_Slots16,  true,   true,   true) \
    D(OBJECT16,            Object,       JSObject,          JSObject_Slots16,  false,  false,  true) \
    D(OBJECT16_BACKGROUND, Object,       JSObject,          JSObject_Slots16,  true,   true,   true)

#define FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \
 /* AllocKind              TraceKind     TypeName           SizedType          BGFinal Nursery Compact */ \
    D(SCRIPT,              Script,       js::BaseScript,    js::BaseScript,    false,  false,  true) \
    D(SHAPE,               Shape,        js::Shape,         js::Shape,         true,   false,  true) \
    D(ACCESSOR_SHAPE,      Shape,        js::AccessorShape, js::AccessorShape, true,   false,  true) \
    D(BASE_SHAPE,          BaseShape,    js::BaseShape,     js::BaseShape,     true,   false,  true) \
    D(OBJECT_GROUP,        ObjectGroup,  js::ObjectGroup,   js::ObjectGroup,   true,   false,  true) \
    D(EXTERNAL_STRING,     String,       JSExternalString,  JSExternalString,  true,   false,  true) \
    D(FAT_INLINE_ATOM,     String,       js::FatInlineAtom, js::FatInlineAtom, true,   false,  false) \
    D(ATOM,                String,       js::NormalAtom,    js::NormalAtom,    true,   false,  false) \
    D(SYMBOL,              Symbol,       JS::Symbol,        JS::Symbol,        true,   false,  false) \
    D(JITCODE,             JitCode,      js::jit::JitCode,  js::jit::JitCode,  false,  false,  false) \
    D(SCOPE,               Scope,        js::Scope,         js::Scope,         true,   false,  true) \
    D(REGEXP_SHARED,       RegExpShared, js::RegExpShared,  js::RegExpShared,  true,   false,  true)

#define FOR_EACH_NONOBJECT_NURSERY_ALLOCKIND(D) \
 /* AllocKind              TraceKind     TypeName           SizedType          BGFinal Nursery Compact */ \
    D(BIGINT,              BigInt,       JS::BigInt,        JS::BigInt,        true,   true,  true)

#define FOR_EACH_NURSERY_STRING_ALLOCKIND(D) \
    D(FAT_INLINE_STRING,   String,        JSFatInlineString, JSFatInlineString, true,   true,  true) \
    D(STRING,              String,        JSString,          JSString,          true,   true,  true)
// clang-format on

#define FOR_EACH_NONOBJECT_ALLOCKIND(D)      \
  FOR_EACH_NONOBJECT_NONNURSERY_ALLOCKIND(D) \
  FOR_EACH_NONOBJECT_NURSERY_ALLOCKIND(D)    \
  FOR_EACH_NURSERY_STRING_ALLOCKIND(D)

#define FOR_EACH_ALLOCKIND(D)  \
  FOR_EACH_OBJECT_ALLOCKIND(D) \
  FOR_EACH_NONOBJECT_ALLOCKIND(D)

#define DEFINE_ALLOC_KIND(allocKind, _1, _2, _3, _4, _5, _6) allocKind,
enum class AllocKind : uint8_t {
  // clang-format off
    FOR_EACH_OBJECT_ALLOCKIND(DEFINE_ALLOC_KIND)

    OBJECT_LIMIT,
    OBJECT_LAST = OBJECT_LIMIT - 1,

    FOR_EACH_NONOBJECT_ALLOCKIND(DEFINE_ALLOC_KIND)

    LIMIT,
    LAST = LIMIT - 1,

    FIRST = 0,
    OBJECT_FIRST = FUNCTION // Hardcoded to first object kind.
  // clang-format on
};
#undef DEFINE_ALLOC_KIND

static_assert(int(AllocKind::FIRST) == 0,
              "Various places depend on AllocKind starting at 0");
static_assert(int(AllocKind::OBJECT_FIRST) == 0,
              "OBJECT_FIRST must be defined as the first object kind");

constexpr size_t AllocKindCount = size_t(AllocKind::LIMIT);

inline bool IsAllocKind(AllocKind kind) {
  return kind >= AllocKind::FIRST && kind <= AllocKind::LIMIT;
}

inline bool IsValidAllocKind(AllocKind kind) {
  return kind >= AllocKind::FIRST && kind <= AllocKind::LAST;
}

const char* AllocKindName(AllocKind kind);

inline bool IsObjectAllocKind(AllocKind kind) {
  return kind >= AllocKind::OBJECT_FIRST && kind <= AllocKind::OBJECT_LAST;
}

inline bool IsShapeAllocKind(AllocKind kind) {
  return kind == AllocKind::SHAPE || kind == AllocKind::ACCESSOR_SHAPE;
}

// Returns a sequence for use in a range-based for loop,
// to iterate over all alloc kinds.
inline auto AllAllocKinds() {
  return mozilla::MakeEnumeratedRange(AllocKind::FIRST, AllocKind::LIMIT);
}

// Returns a sequence for use in a range-based for loop,
// to iterate over all object alloc kinds.
inline auto ObjectAllocKinds() {
  return mozilla::MakeEnumeratedRange(AllocKind::OBJECT_FIRST,
                                      AllocKind::OBJECT_LIMIT);
}

// Returns a sequence for use in a range-based for loop,
// to iterate over alloc kinds from |first| to |limit|, exclusive.
inline auto SomeAllocKinds(AllocKind first = AllocKind::FIRST,
                           AllocKind limit = AllocKind::LIMIT) {
  MOZ_ASSERT(IsAllocKind(first), "|first| is not a valid AllocKind!");
  MOZ_ASSERT(IsAllocKind(limit), "|limit| is not a valid AllocKind!");
  return mozilla::MakeEnumeratedRange(first, limit);
}

// AllAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
// with each index corresponding to a particular alloc kind.
template <typename ValueType>
using AllAllocKindArray =
    mozilla::EnumeratedArray<AllocKind, AllocKind::LIMIT, ValueType>;

// ObjectAllocKindArray<ValueType> gives an enumerated array of ValueTypes,
// with each index corresponding to a particular object alloc kind.
template <typename ValueType>
using ObjectAllocKindArray =
    mozilla::EnumeratedArray<AllocKind, AllocKind::OBJECT_LIMIT, ValueType>;

static inline JS::TraceKind MapAllocToTraceKind(AllocKind kind) {
  static const JS::TraceKind map[] = {
#define EXPAND_ELEMENT(allocKind, traceKind, type, sizedType, bgFinal, \
                       nursery, compact)                               \
  JS::TraceKind::traceKind,
      FOR_EACH_ALLOCKIND(EXPAND_ELEMENT)
#undef EXPAND_ELEMENT
  };

  static_assert(std::size(map) == AllocKindCount,
                "AllocKind-to-TraceKind mapping must be in sync");
  return map[size_t(kind)];
}

static inline bool IsNurseryAllocable(AllocKind kind) {
  MOZ_ASSERT(IsValidAllocKind(kind));

  static const bool map[] = {
#define DEFINE_NURSERY_ALLOCABLE(_1, _2, _3, _4, _5, nursery, _6) nursery,
      FOR_EACH_ALLOCKIND(DEFINE_NURSERY_ALLOCABLE)
#undef DEFINE_NURSERY_ALLOCABLE
  };

  static_assert(std::size(map) == AllocKindCount,
                "IsNurseryAllocable sanity check");
  return map[size_t(kind)];
}

static inline bool IsBackgroundFinalized(AllocKind kind) {
  MOZ_ASSERT(IsValidAllocKind(kind));

  static const bool map[] = {
#define DEFINE_BACKGROUND_FINALIZED(_1, _2, _3, _4, bgFinal, _5, _6) bgFinal,
      FOR_EACH_ALLOCKIND(DEFINE_BACKGROUND_FINALIZED)
#undef DEFINE_BACKGROUND_FINALIZED
  };

  static_assert(std::size(map) == AllocKindCount,
                "IsBackgroundFinalized sanity check");
  return map[size_t(kind)];
}

static inline bool IsForegroundFinalized(AllocKind kind) {
  return !IsBackgroundFinalized(kind);
}

static inline bool IsCompactingKind(AllocKind kind) {
  MOZ_ASSERT(IsValidAllocKind(kind));

  static const bool map[] = {
#define DEFINE_COMPACTING_KIND(_1, _2, _3, _4, _5, _6, compact) compact,
      FOR_EACH_ALLOCKIND(DEFINE_COMPACTING_KIND)
#undef DEFINE_COMPACTING_KIND
  };

  static_assert(std::size(map) == AllocKindCount,
                "IsCompactingKind sanity check");
  return map[size_t(kind)];
}

static inline bool IsMovableKind(AllocKind kind) {
  return IsNurseryAllocable(kind) || IsCompactingKind(kind);
}

} /* namespace gc */
} /* namespace js */

#endif /* gc_AllocKind_h */