1// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_ELEMENTS_KIND_H_
6#define V8_ELEMENTS_KIND_H_
7
8#include "src/base/macros.h"
9#include "src/checks.h"
10#include "src/utils.h"
11
12namespace v8 {
13namespace internal {
14
15// V has parameters (Type, type, TYPE, C type)
16#define TYPED_ARRAYS(V) \
17 V(Uint8, uint8, UINT8, uint8_t) \
18 V(Int8, int8, INT8, int8_t) \
19 V(Uint16, uint16, UINT16, uint16_t) \
20 V(Int16, int16, INT16, int16_t) \
21 V(Uint32, uint32, UINT32, uint32_t) \
22 V(Int32, int32, INT32, int32_t) \
23 V(Float32, float32, FLOAT32, float) \
24 V(Float64, float64, FLOAT64, double) \
25 V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t) \
26 V(BigUint64, biguint64, BIGUINT64, uint64_t) \
27 V(BigInt64, bigint64, BIGINT64, int64_t)
28
29enum ElementsKind : uint8_t {
30 // The "fast" kind for elements that only contain SMI values. Must be first
31 // to make it possible to efficiently check maps for this kind.
32 PACKED_SMI_ELEMENTS,
33 HOLEY_SMI_ELEMENTS,
34
35 // The "fast" kind for tagged values. Must be second to make it possible to
36 // efficiently check maps for this and the PACKED_SMI_ELEMENTS kind
37 // together at once.
38 PACKED_ELEMENTS,
39 HOLEY_ELEMENTS,
40
41 // The "fast" kind for unwrapped, non-tagged double values.
42 PACKED_DOUBLE_ELEMENTS,
43 HOLEY_DOUBLE_ELEMENTS,
44
45 // The sealed, frozen kind for packed elements.
46 PACKED_SEALED_ELEMENTS,
47 PACKED_FROZEN_ELEMENTS,
48
49 // The "slow" kind.
50 DICTIONARY_ELEMENTS,
51
52 // Elements kind of the "arguments" object (only in sloppy mode).
53 FAST_SLOPPY_ARGUMENTS_ELEMENTS,
54 SLOW_SLOPPY_ARGUMENTS_ELEMENTS,
55
56 // For string wrapper objects ("new String('...')"), the string's characters
57 // are overlaid onto a regular elements backing store.
58 FAST_STRING_WRAPPER_ELEMENTS,
59 SLOW_STRING_WRAPPER_ELEMENTS,
60
61// Fixed typed arrays.
62#define TYPED_ARRAY_ELEMENTS_KIND(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
63 TYPED_ARRAYS(TYPED_ARRAY_ELEMENTS_KIND)
64#undef TYPED_ARRAY_ELEMENTS_KIND
65
66 // Sentinel ElementsKind for objects with no elements.
67 NO_ELEMENTS,
68
69 // Derived constants from ElementsKind.
70 FIRST_ELEMENTS_KIND = PACKED_SMI_ELEMENTS,
71 LAST_ELEMENTS_KIND = BIGINT64_ELEMENTS,
72 FIRST_FAST_ELEMENTS_KIND = PACKED_SMI_ELEMENTS,
73 LAST_FAST_ELEMENTS_KIND = HOLEY_DOUBLE_ELEMENTS,
74 FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_ELEMENTS,
75 LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = BIGINT64_ELEMENTS,
76 TERMINAL_FAST_ELEMENTS_KIND = HOLEY_ELEMENTS,
77 LAST_FROZEN_ELEMENTS_KIND = PACKED_FROZEN_ELEMENTS,
78
79// Alias for kSystemPointerSize-sized elements
80#ifdef V8_COMPRESS_POINTERS
81 SYSTEM_POINTER_ELEMENTS = PACKED_DOUBLE_ELEMENTS,
82#else
83 SYSTEM_POINTER_ELEMENTS = PACKED_ELEMENTS,
84#endif
85};
86
87constexpr int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
88constexpr int kFastElementsKindCount =
89 LAST_FAST_ELEMENTS_KIND - FIRST_FAST_ELEMENTS_KIND + 1;
90
91// The number to add to a packed elements kind to reach a holey elements kind
92constexpr int kFastElementsKindPackedToHoley =
93 HOLEY_SMI_ELEMENTS - PACKED_SMI_ELEMENTS;
94
95V8_EXPORT_PRIVATE int ElementsKindToShiftSize(ElementsKind elements_kind);
96V8_EXPORT_PRIVATE int ElementsKindToByteSize(ElementsKind elements_kind);
97int GetDefaultHeaderSizeForElementsKind(ElementsKind elements_kind);
98const char* ElementsKindToString(ElementsKind kind);
99
100inline ElementsKind GetInitialFastElementsKind() { return PACKED_SMI_ELEMENTS; }
101
102ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_number);
103int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind);
104
105ElementsKind GetNextTransitionElementsKind(ElementsKind elements_kind);
106
107inline bool IsDictionaryElementsKind(ElementsKind kind) {
108 return kind == DICTIONARY_ELEMENTS;
109}
110
111inline bool IsSloppyArgumentsElementsKind(ElementsKind kind) {
112 return IsInRange(kind, FAST_SLOPPY_ARGUMENTS_ELEMENTS,
113 SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
114}
115
116inline bool IsStringWrapperElementsKind(ElementsKind kind) {
117 return IsInRange(kind, FAST_STRING_WRAPPER_ELEMENTS,
118 SLOW_STRING_WRAPPER_ELEMENTS);
119}
120
121inline bool IsFixedTypedArrayElementsKind(ElementsKind kind) {
122 return IsInRange(kind, FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
123 LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
124}
125
126inline bool IsTerminalElementsKind(ElementsKind kind) {
127 return kind == TERMINAL_FAST_ELEMENTS_KIND ||
128 IsFixedTypedArrayElementsKind(kind);
129}
130
131inline bool IsFastElementsKind(ElementsKind kind) {
132 STATIC_ASSERT(FIRST_FAST_ELEMENTS_KIND == 0);
133 return kind <= LAST_FAST_ELEMENTS_KIND;
134}
135
136inline bool IsTransitionElementsKind(ElementsKind kind) {
137 return IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind) ||
138 kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS ||
139 kind == FAST_STRING_WRAPPER_ELEMENTS;
140}
141
142inline bool IsDoubleElementsKind(ElementsKind kind) {
143 return IsInRange(kind, PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS);
144}
145
146
147inline bool IsFixedFloatElementsKind(ElementsKind kind) {
148 return kind == FLOAT32_ELEMENTS || kind == FLOAT64_ELEMENTS;
149}
150
151
152inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) {
153 return IsDoubleElementsKind(kind) || IsFixedFloatElementsKind(kind);
154}
155
156inline bool IsFrozenOrSealedElementsKind(ElementsKind kind) {
157 return IsInRange(kind, PACKED_SEALED_ELEMENTS, PACKED_FROZEN_ELEMENTS);
158}
159
160inline bool IsSealedElementsKind(ElementsKind kind) {
161 return kind == PACKED_SEALED_ELEMENTS;
162}
163
164inline bool IsSmiOrObjectElementsKind(ElementsKind kind) {
165 return kind == PACKED_SMI_ELEMENTS || kind == HOLEY_SMI_ELEMENTS ||
166 kind == PACKED_ELEMENTS || kind == HOLEY_ELEMENTS;
167}
168
169inline bool IsSmiElementsKind(ElementsKind kind) {
170 return IsInRange(kind, PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS);
171}
172
173inline bool IsFastNumberElementsKind(ElementsKind kind) {
174 return IsSmiElementsKind(kind) || IsDoubleElementsKind(kind);
175}
176
177inline bool IsObjectElementsKind(ElementsKind kind) {
178 return IsInRange(kind, PACKED_ELEMENTS, HOLEY_ELEMENTS);
179}
180
181inline bool IsHoleyElementsKind(ElementsKind kind) {
182 return kind == HOLEY_SMI_ELEMENTS || kind == HOLEY_DOUBLE_ELEMENTS ||
183 kind == HOLEY_ELEMENTS;
184}
185
186inline bool IsHoleyOrDictionaryElementsKind(ElementsKind kind) {
187 return IsHoleyElementsKind(kind) || kind == DICTIONARY_ELEMENTS;
188}
189
190
191inline bool IsFastPackedElementsKind(ElementsKind kind) {
192 return kind == PACKED_SMI_ELEMENTS || kind == PACKED_DOUBLE_ELEMENTS ||
193 kind == PACKED_ELEMENTS;
194}
195
196
197inline ElementsKind GetPackedElementsKind(ElementsKind holey_kind) {
198 if (holey_kind == HOLEY_SMI_ELEMENTS) {
199 return PACKED_SMI_ELEMENTS;
200 }
201 if (holey_kind == HOLEY_DOUBLE_ELEMENTS) {
202 return PACKED_DOUBLE_ELEMENTS;
203 }
204 if (holey_kind == HOLEY_ELEMENTS) {
205 return PACKED_ELEMENTS;
206 }
207 return holey_kind;
208}
209
210
211inline ElementsKind GetHoleyElementsKind(ElementsKind packed_kind) {
212 if (packed_kind == PACKED_SMI_ELEMENTS) {
213 return HOLEY_SMI_ELEMENTS;
214 }
215 if (packed_kind == PACKED_DOUBLE_ELEMENTS) {
216 return HOLEY_DOUBLE_ELEMENTS;
217 }
218 if (packed_kind == PACKED_ELEMENTS) {
219 return HOLEY_ELEMENTS;
220 }
221 return packed_kind;
222}
223
224inline bool UnionElementsKindUptoPackedness(ElementsKind* a_out,
225 ElementsKind b) {
226 // Assert that the union of two ElementKinds can be computed via std::max.
227 static_assert(PACKED_SMI_ELEMENTS < HOLEY_SMI_ELEMENTS,
228 "ElementsKind union not computable via std::max.");
229 static_assert(PACKED_ELEMENTS < HOLEY_ELEMENTS,
230 "ElementsKind union not computable via std::max.");
231 static_assert(PACKED_DOUBLE_ELEMENTS < HOLEY_DOUBLE_ELEMENTS,
232 "ElementsKind union not computable via std::max.");
233 ElementsKind a = *a_out;
234 switch (a) {
235 case HOLEY_SMI_ELEMENTS:
236 case PACKED_SMI_ELEMENTS:
237 if (b == PACKED_SMI_ELEMENTS || b == HOLEY_SMI_ELEMENTS) {
238 *a_out = std::max(a, b);
239 return true;
240 }
241 break;
242 case PACKED_ELEMENTS:
243 case HOLEY_ELEMENTS:
244 if (b == PACKED_ELEMENTS || b == HOLEY_ELEMENTS) {
245 *a_out = std::max(a, b);
246 return true;
247 }
248 break;
249 case PACKED_DOUBLE_ELEMENTS:
250 case HOLEY_DOUBLE_ELEMENTS:
251 if (b == PACKED_DOUBLE_ELEMENTS || b == HOLEY_DOUBLE_ELEMENTS) {
252 *a_out = std::max(a, b);
253 return true;
254 }
255 break;
256 default:
257 break;
258 }
259 return false;
260}
261
262bool UnionElementsKindUptoSize(ElementsKind* a_out, ElementsKind b);
263
264inline ElementsKind FastSmiToObjectElementsKind(ElementsKind from_kind) {
265 DCHECK(IsSmiElementsKind(from_kind));
266 return (from_kind == PACKED_SMI_ELEMENTS) ? PACKED_ELEMENTS : HOLEY_ELEMENTS;
267}
268
269
270inline bool IsSimpleMapChangeTransition(ElementsKind from_kind,
271 ElementsKind to_kind) {
272 return (GetHoleyElementsKind(from_kind) == to_kind) ||
273 (IsSmiElementsKind(from_kind) && IsObjectElementsKind(to_kind));
274}
275
276
277bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
278 ElementsKind to_kind);
279
280
281inline ElementsKind GetMoreGeneralElementsKind(ElementsKind from_kind,
282 ElementsKind to_kind) {
283 if (IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
284 return to_kind;
285 }
286 return from_kind;
287}
288
289
290inline bool IsTransitionableFastElementsKind(ElementsKind from_kind) {
291 return IsFastElementsKind(from_kind) &&
292 from_kind != TERMINAL_FAST_ELEMENTS_KIND;
293}
294
295inline bool ElementsKindEqual(ElementsKind a, ElementsKind b) { return a == b; }
296
297} // namespace internal
298} // namespace v8
299
300#endif // V8_ELEMENTS_KIND_H_
301