elements-kind.h 12.3 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#ifndef V8_OBJECTS_ELEMENTS_KIND_H_
#define V8_OBJECTS_ELEMENTS_KIND_H_
7

8
#include "src/base/bits.h"
9
#include "src/base/bounds.h"
10
#include "src/base/macros.h"
11 12
#include "src/common/checks.h"
#include "src/flags/flags.h"
13 14 15 16

namespace v8 {
namespace internal {

17 18 19 20 21 22 23 24 25 26 27 28 29
// V has parameters (Type, type, TYPE, C type)
#define TYPED_ARRAYS(V)                                  \
  V(Uint8, uint8, UINT8, uint8_t)                        \
  V(Int8, int8, INT8, int8_t)                            \
  V(Uint16, uint16, UINT16, uint16_t)                    \
  V(Int16, int16, INT16, int16_t)                        \
  V(Uint32, uint32, UINT32, uint32_t)                    \
  V(Int32, int32, INT32, int32_t)                        \
  V(Float32, float32, FLOAT32, float)                    \
  V(Float64, float64, FLOAT64, double)                   \
  V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t) \
  V(BigUint64, biguint64, BIGUINT64, uint64_t)           \
  V(BigInt64, bigint64, BIGINT64, int64_t)
30

31
enum ElementsKind : uint8_t {
32 33
  // The "fast" kind for elements that only contain SMI values. Must be first
  // to make it possible to efficiently check maps for this kind.
34 35
  PACKED_SMI_ELEMENTS,
  HOLEY_SMI_ELEMENTS,
36 37

  // The "fast" kind for tagged values. Must be second to make it possible to
38
  // efficiently check maps for this and the PACKED_SMI_ELEMENTS kind
39
  // together at once.
40 41
  PACKED_ELEMENTS,
  HOLEY_ELEMENTS,
42 43

  // The "fast" kind for unwrapped, non-tagged double values.
44 45
  PACKED_DOUBLE_ELEMENTS,
  HOLEY_DOUBLE_ELEMENTS,
46

47 48 49 50
  // The nonextensible kind for elements.
  PACKED_NONEXTENSIBLE_ELEMENTS,
  HOLEY_NONEXTENSIBLE_ELEMENTS,

51
  // The sealed kind for elements.
52
  PACKED_SEALED_ELEMENTS,
53 54 55
  HOLEY_SEALED_ELEMENTS,

  // The frozen kind for elements.
56
  PACKED_FROZEN_ELEMENTS,
57
  HOLEY_FROZEN_ELEMENTS,
58

59 60
  // The "slow" kind.
  DICTIONARY_ELEMENTS,
61

62
  // Elements kind of the "arguments" object (only in sloppy mode).
63 64 65
  FAST_SLOPPY_ARGUMENTS_ELEMENTS,
  SLOW_SLOPPY_ARGUMENTS_ELEMENTS,

66 67 68 69 70
  // For string wrapper objects ("new String('...')"), the string's characters
  // are overlaid onto a regular elements backing store.
  FAST_STRING_WRAPPER_ELEMENTS,
  SLOW_STRING_WRAPPER_ELEMENTS,

71
// Fixed typed arrays.
72
#define TYPED_ARRAY_ELEMENTS_KIND(Type, type, TYPE, ctype) TYPE##_ELEMENTS,
73 74
  TYPED_ARRAYS(TYPED_ARRAY_ELEMENTS_KIND)
#undef TYPED_ARRAY_ELEMENTS_KIND
75

76 77 78 79
  // Sentinel ElementsKind for objects with no elements.
  NO_ELEMENTS,

  // Derived constants from ElementsKind.
80
  FIRST_ELEMENTS_KIND = PACKED_SMI_ELEMENTS,
81
  LAST_ELEMENTS_KIND = BIGINT64_ELEMENTS,
82 83
  FIRST_FAST_ELEMENTS_KIND = PACKED_SMI_ELEMENTS,
  LAST_FAST_ELEMENTS_KIND = HOLEY_DOUBLE_ELEMENTS,
84
  FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_ELEMENTS,
85
  LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = BIGINT64_ELEMENTS,
86
  TERMINAL_FAST_ELEMENTS_KIND = HOLEY_ELEMENTS,
87 88
  FIRST_ANY_NONEXTENSIBLE_ELEMENTS_KIND = PACKED_NONEXTENSIBLE_ELEMENTS,
  LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND = HOLEY_FROZEN_ELEMENTS,
89 90 91 92 93 94 95

// Alias for kSystemPointerSize-sized elements
#ifdef V8_COMPRESS_POINTERS
  SYSTEM_POINTER_ELEMENTS = PACKED_DOUBLE_ELEMENTS,
#else
  SYSTEM_POINTER_ELEMENTS = PACKED_ELEMENTS,
#endif
96 97
};

98 99
constexpr int kElementsKindCount = LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
constexpr int kFastElementsKindCount =
100
    LAST_FAST_ELEMENTS_KIND - FIRST_FAST_ELEMENTS_KIND + 1;
101

102
// The number to add to a packed elements kind to reach a holey elements kind
103
constexpr int kFastElementsKindPackedToHoley =
104
    HOLEY_SMI_ELEMENTS - PACKED_SMI_ELEMENTS;
105

106 107 108 109 110 111 112 113
constexpr int kElementsKindBits = 5;
STATIC_ASSERT((1 << kElementsKindBits) > LAST_ELEMENTS_KIND);
STATIC_ASSERT((1 << (kElementsKindBits - 1)) <= LAST_ELEMENTS_KIND);

constexpr int kFastElementsKindBits = 3;
STATIC_ASSERT((1 << kFastElementsKindBits) > LAST_FAST_ELEMENTS_KIND);
STATIC_ASSERT((1 << (kFastElementsKindBits - 1)) <= LAST_FAST_ELEMENTS_KIND);

114 115
V8_EXPORT_PRIVATE int ElementsKindToShiftSize(ElementsKind elements_kind);
V8_EXPORT_PRIVATE int ElementsKindToByteSize(ElementsKind elements_kind);
116
int GetDefaultHeaderSizeForElementsKind(ElementsKind elements_kind);
117
const char* ElementsKindToString(ElementsKind kind);
118

119
inline ElementsKind GetInitialFastElementsKind() { return PACKED_SMI_ELEMENTS; }
120

121
ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_number);
122 123
int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind);

124
ElementsKind GetNextTransitionElementsKind(ElementsKind elements_kind);
125

126 127 128 129
inline bool IsDictionaryElementsKind(ElementsKind kind) {
  return kind == DICTIONARY_ELEMENTS;
}

130 131 132 133 134 135 136 137
inline bool IsFastArgumentsElementsKind(ElementsKind kind) {
  return kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS;
}

inline bool IsSlowArgumentsElementsKind(ElementsKind kind) {
  return kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS;
}

138
inline bool IsSloppyArgumentsElementsKind(ElementsKind kind) {
139 140
  return base::IsInRange(kind, FAST_SLOPPY_ARGUMENTS_ELEMENTS,
                         SLOW_SLOPPY_ARGUMENTS_ELEMENTS);
141 142
}

143
inline bool IsStringWrapperElementsKind(ElementsKind kind) {
144 145
  return base::IsInRange(kind, FAST_STRING_WRAPPER_ELEMENTS,
                         SLOW_STRING_WRAPPER_ELEMENTS);
146
}
147

148
inline bool IsTypedArrayElementsKind(ElementsKind kind) {
149 150
  return base::IsInRange(kind, FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND,
                         LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
151 152
}

153
inline bool IsTerminalElementsKind(ElementsKind kind) {
154
  return kind == TERMINAL_FAST_ELEMENTS_KIND || IsTypedArrayElementsKind(kind);
155 156
}

157
inline bool IsFastElementsKind(ElementsKind kind) {
158
  STATIC_ASSERT(FIRST_FAST_ELEMENTS_KIND == 0);
159
  return kind <= LAST_FAST_ELEMENTS_KIND;
160 161
}

162
inline bool IsTransitionElementsKind(ElementsKind kind) {
163
  return IsFastElementsKind(kind) || IsTypedArrayElementsKind(kind) ||
164 165
         kind == FAST_SLOPPY_ARGUMENTS_ELEMENTS ||
         kind == FAST_STRING_WRAPPER_ELEMENTS;
166 167
}

168
inline bool IsDoubleElementsKind(ElementsKind kind) {
169
  return base::IsInRange(kind, PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS);
170 171
}

172 173 174 175
inline bool IsFixedFloatElementsKind(ElementsKind kind) {
  return kind == FLOAT32_ELEMENTS || kind == FLOAT64_ELEMENTS;
}

176
inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) {
177
  return IsDoubleElementsKind(kind) || IsFixedFloatElementsKind(kind);
178 179
}

180
// This predicate is used for disabling respective functionality in builtins.
181
inline bool IsAnyNonextensibleElementsKindUnchecked(ElementsKind kind) {
182 183
  return base::IsInRange(kind, FIRST_ANY_NONEXTENSIBLE_ELEMENTS_KIND,
                         LAST_ANY_NONEXTENSIBLE_ELEMENTS_KIND);
184 185
}

186 187
inline bool IsAnyNonextensibleElementsKind(ElementsKind kind) {
  DCHECK_IMPLIES(IsAnyNonextensibleElementsKindUnchecked(kind),
188
                 FLAG_enable_sealed_frozen_elements_kind);
189 190 191 192
  return IsAnyNonextensibleElementsKindUnchecked(kind);
}

inline bool IsNonextensibleElementsKind(ElementsKind kind) {
193 194
  DCHECK_IMPLIES(base::IsInRange(kind, PACKED_NONEXTENSIBLE_ELEMENTS,
                                 HOLEY_NONEXTENSIBLE_ELEMENTS),
195
                 FLAG_enable_sealed_frozen_elements_kind);
196 197
  return base::IsInRange(kind, PACKED_NONEXTENSIBLE_ELEMENTS,
                         HOLEY_NONEXTENSIBLE_ELEMENTS);
198 199
}

200
inline bool IsSealedElementsKind(ElementsKind kind) {
201 202 203 204
  DCHECK_IMPLIES(
      base::IsInRange(kind, PACKED_SEALED_ELEMENTS, HOLEY_SEALED_ELEMENTS),
      FLAG_enable_sealed_frozen_elements_kind);
  return base::IsInRange(kind, PACKED_SEALED_ELEMENTS, HOLEY_SEALED_ELEMENTS);
205 206
}

207
inline bool IsFrozenElementsKind(ElementsKind kind) {
208 209 210 211
  DCHECK_IMPLIES(
      base::IsInRange(kind, PACKED_FROZEN_ELEMENTS, HOLEY_FROZEN_ELEMENTS),
      FLAG_enable_sealed_frozen_elements_kind);
  return base::IsInRange(kind, PACKED_FROZEN_ELEMENTS, HOLEY_FROZEN_ELEMENTS);
212 213
}

214
inline bool IsSmiOrObjectElementsKind(ElementsKind kind) {
215
  return base::IsInRange(kind, PACKED_SMI_ELEMENTS, HOLEY_ELEMENTS);
216 217
}

218
inline bool IsSmiElementsKind(ElementsKind kind) {
219
  return base::IsInRange(kind, PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS);
220 221
}

222
inline bool IsFastNumberElementsKind(ElementsKind kind) {
223
  return IsSmiElementsKind(kind) || IsDoubleElementsKind(kind);
224 225
}

226
inline bool IsObjectElementsKind(ElementsKind kind) {
227
  return base::IsInRange(kind, PACKED_ELEMENTS, HOLEY_ELEMENTS);
228 229
}

230 231 232 233
inline bool IsAnyHoleyNonextensibleElementsKind(ElementsKind kind) {
  DCHECK_IMPLIES(kind == HOLEY_NONEXTENSIBLE_ELEMENTS ||
                     kind == HOLEY_SEALED_ELEMENTS ||
                     kind == HOLEY_FROZEN_ELEMENTS,
234
                 FLAG_enable_sealed_frozen_elements_kind);
235 236
  return kind == HOLEY_NONEXTENSIBLE_ELEMENTS ||
         kind == HOLEY_SEALED_ELEMENTS || kind == HOLEY_FROZEN_ELEMENTS;
237 238
}

239
inline bool IsHoleyElementsKind(ElementsKind kind) {
240
  return kind % 2 == 1 && kind <= HOLEY_DOUBLE_ELEMENTS;
241 242
}

243
inline bool IsHoleyElementsKindForRead(ElementsKind kind) {
244
  return kind % 2 == 1 && kind <= HOLEY_FROZEN_ELEMENTS;
245 246
}

247
inline bool IsHoleyOrDictionaryElementsKind(ElementsKind kind) {
248
  return IsHoleyElementsKindForRead(kind) || kind == DICTIONARY_ELEMENTS;
249 250 251
}

inline bool IsFastPackedElementsKind(ElementsKind kind) {
252
  return kind % 2 == 0 && kind <= PACKED_DOUBLE_ELEMENTS;
253 254 255
}

inline ElementsKind GetPackedElementsKind(ElementsKind holey_kind) {
256 257
  if (holey_kind == HOLEY_SMI_ELEMENTS) {
    return PACKED_SMI_ELEMENTS;
258
  }
259 260
  if (holey_kind == HOLEY_DOUBLE_ELEMENTS) {
    return PACKED_DOUBLE_ELEMENTS;
261
  }
262 263
  if (holey_kind == HOLEY_ELEMENTS) {
    return PACKED_ELEMENTS;
264 265 266 267 268
  }
  return holey_kind;
}

inline ElementsKind GetHoleyElementsKind(ElementsKind packed_kind) {
269 270
  if (packed_kind == PACKED_SMI_ELEMENTS) {
    return HOLEY_SMI_ELEMENTS;
271
  }
272 273
  if (packed_kind == PACKED_DOUBLE_ELEMENTS) {
    return HOLEY_DOUBLE_ELEMENTS;
274
  }
275 276
  if (packed_kind == PACKED_ELEMENTS) {
    return HOLEY_ELEMENTS;
277
  }
278 279 280
  if (packed_kind == PACKED_NONEXTENSIBLE_ELEMENTS) {
    return HOLEY_NONEXTENSIBLE_ELEMENTS;
  }
281 282 283
  return packed_kind;
}

284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
inline bool UnionElementsKindUptoPackedness(ElementsKind* a_out,
                                            ElementsKind b) {
  // Assert that the union of two ElementKinds can be computed via std::max.
  static_assert(PACKED_SMI_ELEMENTS < HOLEY_SMI_ELEMENTS,
                "ElementsKind union not computable via std::max.");
  static_assert(PACKED_ELEMENTS < HOLEY_ELEMENTS,
                "ElementsKind union not computable via std::max.");
  static_assert(PACKED_DOUBLE_ELEMENTS < HOLEY_DOUBLE_ELEMENTS,
                "ElementsKind union not computable via std::max.");
  ElementsKind a = *a_out;
  switch (a) {
    case HOLEY_SMI_ELEMENTS:
    case PACKED_SMI_ELEMENTS:
      if (b == PACKED_SMI_ELEMENTS || b == HOLEY_SMI_ELEMENTS) {
        *a_out = std::max(a, b);
        return true;
      }
      break;
    case PACKED_ELEMENTS:
    case HOLEY_ELEMENTS:
      if (b == PACKED_ELEMENTS || b == HOLEY_ELEMENTS) {
        *a_out = std::max(a, b);
        return true;
      }
      break;
    case PACKED_DOUBLE_ELEMENTS:
    case HOLEY_DOUBLE_ELEMENTS:
      if (b == PACKED_DOUBLE_ELEMENTS || b == HOLEY_DOUBLE_ELEMENTS) {
        *a_out = std::max(a, b);
        return true;
      }
      break;
    default:
      break;
  }
  return false;
}
321

322
bool UnionElementsKindUptoSize(ElementsKind* a_out, ElementsKind b);
323

324
inline ElementsKind FastSmiToObjectElementsKind(ElementsKind from_kind) {
325
  DCHECK(IsSmiElementsKind(from_kind));
326
  return (from_kind == PACKED_SMI_ELEMENTS) ? PACKED_ELEMENTS : HOLEY_ELEMENTS;
327 328 329 330 331
}

inline bool IsSimpleMapChangeTransition(ElementsKind from_kind,
                                        ElementsKind to_kind) {
  return (GetHoleyElementsKind(from_kind) == to_kind) ||
332
         (IsSmiElementsKind(from_kind) && IsObjectElementsKind(to_kind));
333 334 335 336 337
}

bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind,
                                         ElementsKind to_kind);

338 339 340 341 342 343 344 345
inline ElementsKind GetMoreGeneralElementsKind(ElementsKind from_kind,
                                               ElementsKind to_kind) {
  if (IsMoreGeneralElementsKindTransition(from_kind, to_kind)) {
    return to_kind;
  }
  return from_kind;
}

346 347
inline bool IsTransitionableFastElementsKind(ElementsKind from_kind) {
  return IsFastElementsKind(from_kind) &&
348
         from_kind != TERMINAL_FAST_ELEMENTS_KIND;
349 350
}

351
inline bool ElementsKindEqual(ElementsKind a, ElementsKind b) { return a == b; }
352

353 354
}  // namespace internal
}  // namespace v8
355

356
#endif  // V8_OBJECTS_ELEMENTS_KIND_H_