// 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/elements-kind.h" #include "src/base/lazy-instance.h" #include "src/elements.h" #include "src/objects-inl.h" #include "src/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 HOLEY_SMI_ELEMENTS: case HOLEY_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 kPointerSizeLog2; 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 (IsFixedTypedArrayElementsKind(elements_kind)) { return 0; } else { return FixedArray::kHeaderSize - kHeapObjectTag; } } const char* ElementsKindToString(ElementsKind kind) { ElementsAccessor* accessor = ElementsAccessor::ForKind(kind); return accessor->name(); } struct InitializeFastElementsKindSequence { static void Construct(void* fast_elements_kind_sequence_ptr_arg) { auto fast_elements_kind_sequence_ptr = reinterpret_cast(fast_elements_kind_sequence_ptr_arg); ElementsKind* fast_elements_kind_sequence = new ElementsKind[kFastElementsKindCount]; *fast_elements_kind_sequence_ptr = fast_elements_kind_sequence; STATIC_ASSERT(PACKED_SMI_ELEMENTS == FIRST_FAST_ELEMENTS_KIND); fast_elements_kind_sequence[0] = PACKED_SMI_ELEMENTS; fast_elements_kind_sequence[1] = HOLEY_SMI_ELEMENTS; fast_elements_kind_sequence[2] = PACKED_DOUBLE_ELEMENTS; fast_elements_kind_sequence[3] = HOLEY_DOUBLE_ELEMENTS; fast_elements_kind_sequence[4] = PACKED_ELEMENTS; fast_elements_kind_sequence[5] = HOLEY_ELEMENTS; // 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); } }; static base::LazyInstance::type fast_elements_kind_sequence = LAZY_INSTANCE_INITIALIZER; ElementsKind GetFastElementsKindFromSequenceIndex(int sequence_number) { DCHECK(sequence_number >= 0 && sequence_number < kFastElementsKindCount); return fast_elements_kind_sequence.Get()[sequence_number]; } int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind) { for (int i = 0; i < kFastElementsKindCount; ++i) { if (fast_elements_kind_sequence.Get()[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(!IsFixedTypedArrayElementsKind(from_kind)); DCHECK(!IsFixedTypedArrayElementsKind(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