// Copyright 2012 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/objects/elements-kind.h" #include "src/base/lazy-instance.h" #include "src/objects/elements.h" #include "src/objects/objects-inl.h" #include "src/objects/objects.h" namespace v8 { namespace internal { int ElementsKindToShiftSize(ElementsKind elements_kind) { switch (elements_kind) { case UINT8_ELEMENTS: case INT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: return 0; case UINT16_ELEMENTS: case INT16_ELEMENTS: return 1; case UINT32_ELEMENTS: case INT32_ELEMENTS: case FLOAT32_ELEMENTS: return 2; case PACKED_DOUBLE_ELEMENTS: case HOLEY_DOUBLE_ELEMENTS: case FLOAT64_ELEMENTS: case BIGINT64_ELEMENTS: case BIGUINT64_ELEMENTS: return 3; case PACKED_SMI_ELEMENTS: case PACKED_ELEMENTS: case PACKED_FROZEN_ELEMENTS: case PACKED_SEALED_ELEMENTS: case PACKED_NONEXTENSIBLE_ELEMENTS: case HOLEY_SMI_ELEMENTS: case HOLEY_ELEMENTS: case HOLEY_FROZEN_ELEMENTS: case HOLEY_SEALED_ELEMENTS: case HOLEY_NONEXTENSIBLE_ELEMENTS: case DICTIONARY_ELEMENTS: case FAST_SLOPPY_ARGUMENTS_ELEMENTS: case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: case FAST_STRING_WRAPPER_ELEMENTS: case SLOW_STRING_WRAPPER_ELEMENTS: return kTaggedSizeLog2; case NO_ELEMENTS: UNREACHABLE(); } UNREACHABLE(); } int ElementsKindToByteSize(ElementsKind elements_kind) { return 1 << ElementsKindToShiftSize(elements_kind); } int GetDefaultHeaderSizeForElementsKind(ElementsKind elements_kind) { STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize); if (IsTypedArrayElementsKind(elements_kind)) { return 0; } else { return FixedArray::kHeaderSize - kHeapObjectTag; } } const char* ElementsKindToString(ElementsKind kind) { switch (kind) { case PACKED_SMI_ELEMENTS: return "PACKED_SMI_ELEMENTS"; case HOLEY_SMI_ELEMENTS: return "HOLEY_SMI_ELEMENTS"; case PACKED_ELEMENTS: return "PACKED_ELEMENTS"; case HOLEY_ELEMENTS: return "HOLEY_ELEMENTS"; case PACKED_DOUBLE_ELEMENTS: return "PACKED_DOUBLE_ELEMENTS"; case HOLEY_DOUBLE_ELEMENTS: return "HOLEY_DOUBLE_ELEMENTS"; case PACKED_NONEXTENSIBLE_ELEMENTS: return "PACKED_NONEXTENSIBLE_ELEMENTS"; case HOLEY_NONEXTENSIBLE_ELEMENTS: return "HOLEY_NONEXTENSIBLE_ELEMENTS"; case PACKED_SEALED_ELEMENTS: return "PACKED_SEALED_ELEMENTS"; case HOLEY_SEALED_ELEMENTS: return "HOLEY_SEALED_ELEMENTS"; case PACKED_FROZEN_ELEMENTS: return "PACKED_FROZEN_ELEMENTS"; case HOLEY_FROZEN_ELEMENTS: return "HOLEY_FROZEN_ELEMENTS"; case DICTIONARY_ELEMENTS: return "DICTIONARY_ELEMENTS"; case FAST_SLOPPY_ARGUMENTS_ELEMENTS: return "FAST_SLOPPY_ARGUMENTS_ELEMENTS"; case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: return "SLOW_SLOPPY_ARGUMENTS_ELEMENTS"; case FAST_STRING_WRAPPER_ELEMENTS: return "FAST_STRING_WRAPPER_ELEMENTS"; case SLOW_STRING_WRAPPER_ELEMENTS: return "SLOW_STRING_WRAPPER_ELEMENTS"; #define PRINT_NAME(Type, type, TYPE, _) \ case TYPE##_ELEMENTS: \ return #TYPE "ELEMENTS"; TYPED_ARRAYS(PRINT_NAME); #undef PRINT_NAME case NO_ELEMENTS: return "NO_ELEMENTS"; } } const ElementsKind kFastElementsKindSequence[kFastElementsKindCount] = { PACKED_SMI_ELEMENTS, // 0 HOLEY_SMI_ELEMENTS, // 1 PACKED_DOUBLE_ELEMENTS, // 2 HOLEY_DOUBLE_ELEMENTS, // 3 PACKED_ELEMENTS, // 4 HOLEY_ELEMENTS // 5 }; STATIC_ASSERT(PACKED_SMI_ELEMENTS == FIRST_FAST_ELEMENTS_KIND); // Verify that kFastElementsKindPackedToHoley is correct. STATIC_ASSERT(PACKED_SMI_ELEMENTS + kFastElementsKindPackedToHoley == HOLEY_SMI_ELEMENTS); STATIC_ASSERT(PACKED_DOUBLE_ELEMENTS + kFastElementsKindPackedToHoley == HOLEY_DOUBLE_ELEMENTS); STATIC_ASSERT(PACKED_ELEMENTS + kFastElementsKindPackedToHoley == HOLEY_ELEMENTS); ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_number) { DCHECK(sequence_number >= 0 && sequence_number < kFastElementsKindCount); return kFastElementsKindSequence[sequence_number]; } int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind) { for (int i = 0; i < kFastElementsKindCount; ++i) { if (kFastElementsKindSequence[i] == elements_kind) { return i; } } UNREACHABLE(); } ElementsKind GetNextTransitionElementsKind(ElementsKind kind) { int index = GetSequenceIndexFromFastElementsKind(kind); return GetFastElementsKindFromSequenceIndex(index + 1); } static inline bool IsFastTransitionTarget(ElementsKind elements_kind) { return IsFastElementsKind(elements_kind) || elements_kind == DICTIONARY_ELEMENTS; } bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind, ElementsKind to_kind) { if (!IsFastElementsKind(from_kind)) return false; if (!IsFastTransitionTarget(to_kind)) return false; DCHECK(!IsTypedArrayElementsKind(from_kind)); DCHECK(!IsTypedArrayElementsKind(to_kind)); switch (from_kind) { case PACKED_SMI_ELEMENTS: return to_kind != PACKED_SMI_ELEMENTS; case HOLEY_SMI_ELEMENTS: return to_kind != PACKED_SMI_ELEMENTS && to_kind != HOLEY_SMI_ELEMENTS; case PACKED_DOUBLE_ELEMENTS: return to_kind != PACKED_SMI_ELEMENTS && to_kind != HOLEY_SMI_ELEMENTS && to_kind != PACKED_DOUBLE_ELEMENTS; case HOLEY_DOUBLE_ELEMENTS: return to_kind == PACKED_ELEMENTS || to_kind == HOLEY_ELEMENTS; case PACKED_ELEMENTS: return to_kind == HOLEY_ELEMENTS; case HOLEY_ELEMENTS: return false; default: return false; } } bool UnionElementsKindUptoSize(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(HOLEY_SMI_ELEMENTS < PACKED_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 PACKED_SMI_ELEMENTS: switch (b) { case PACKED_SMI_ELEMENTS: case HOLEY_SMI_ELEMENTS: case PACKED_ELEMENTS: case HOLEY_ELEMENTS: *a_out = b; return true; default: return false; } case HOLEY_SMI_ELEMENTS: switch (b) { case PACKED_SMI_ELEMENTS: case HOLEY_SMI_ELEMENTS: *a_out = HOLEY_SMI_ELEMENTS; return true; case PACKED_ELEMENTS: case HOLEY_ELEMENTS: *a_out = HOLEY_ELEMENTS; return true; default: return false; } case PACKED_ELEMENTS: switch (b) { case PACKED_SMI_ELEMENTS: case PACKED_ELEMENTS: *a_out = PACKED_ELEMENTS; return true; case HOLEY_SMI_ELEMENTS: case HOLEY_ELEMENTS: *a_out = HOLEY_ELEMENTS; return true; default: return false; } case HOLEY_ELEMENTS: switch (b) { case PACKED_SMI_ELEMENTS: case HOLEY_SMI_ELEMENTS: case PACKED_ELEMENTS: case HOLEY_ELEMENTS: *a_out = HOLEY_ELEMENTS; return true; default: return false; } break; case PACKED_DOUBLE_ELEMENTS: switch (b) { case PACKED_DOUBLE_ELEMENTS: case HOLEY_DOUBLE_ELEMENTS: *a_out = b; return true; default: return false; } case HOLEY_DOUBLE_ELEMENTS: switch (b) { case PACKED_DOUBLE_ELEMENTS: case HOLEY_DOUBLE_ELEMENTS: *a_out = HOLEY_DOUBLE_ELEMENTS; return true; default: return false; } break; default: break; } return false; } } // namespace internal } // namespace v8