diff options
Diffstat (limited to 'src/3rdparty/v8/src/elements.cc')
-rw-r--r-- | src/3rdparty/v8/src/elements.cc | 636 |
1 files changed, 484 insertions, 152 deletions
diff --git a/src/3rdparty/v8/src/elements.cc b/src/3rdparty/v8/src/elements.cc index 9b8548d..8cb48c6 100644 --- a/src/3rdparty/v8/src/elements.cc +++ b/src/3rdparty/v8/src/elements.cc @@ -39,8 +39,14 @@ // Inheritance hierarchy: // - ElementsAccessorBase (abstract) // - FastElementsAccessor (abstract) -// - FastObjectElementsAccessor +// - FastSmiOrObjectElementsAccessor +// - FastPackedSmiElementsAccessor +// - FastHoleySmiElementsAccessor +// - FastPackedObjectElementsAccessor +// - FastHoleyObjectElementsAccessor // - FastDoubleElementsAccessor +// - FastPackedDoubleElementsAccessor +// - FastHoleyDoubleElementsAccessor // - ExternalElementsAccessor (abstract) // - ExternalByteElementsAccessor // - ExternalUnsignedByteElementsAccessor @@ -59,15 +65,24 @@ namespace v8 { namespace internal { +static const int kPackedSizeNotKnown = -1; + + // First argument in list is the accessor class, the second argument is the // accessor ElementsKind, and the third is the backing store class. Use the // fast element handler for smi-only arrays. The implementation is currently // identical. Note that the order must match that of the ElementsKind enum for // the |accessor_array[]| below to work. #define ELEMENTS_LIST(V) \ - V(FastObjectElementsAccessor, FAST_SMI_ONLY_ELEMENTS, FixedArray) \ - V(FastObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \ - V(FastDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \ + V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray) \ + V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, \ + FixedArray) \ + V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray) \ + V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray) \ + V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, \ + FixedDoubleArray) \ + V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS, \ + FixedDoubleArray) \ V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, \ SeededNumberDictionary) \ V(NonStrictArgumentsElementsAccessor, NON_STRICT_ARGUMENTS_ELEMENTS, \ @@ -139,8 +154,6 @@ void CopyObjectToObjectElements(FixedArray* from, uint32_t to_start, int raw_copy_size) { ASSERT(to->map() != HEAP->fixed_cow_array_map()); - ASSERT(from_kind == FAST_ELEMENTS || from_kind == FAST_SMI_ONLY_ELEMENTS); - ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS); int copy_size = raw_copy_size; if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || @@ -148,7 +161,7 @@ void CopyObjectToObjectElements(FixedArray* from, copy_size = Min(from->length() - from_start, to->length() - to_start); #ifdef DEBUG - // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already + // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already // marked with the hole. if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { for (int i = to_start + copy_size; i < to->length(); ++i) { @@ -160,12 +173,15 @@ void CopyObjectToObjectElements(FixedArray* from, ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && (copy_size + static_cast<int>(from_start)) <= from->length()); if (copy_size == 0) return; + ASSERT(IsFastSmiOrObjectElementsKind(from_kind)); + ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); Address to_address = to->address() + FixedArray::kHeaderSize; Address from_address = from->address() + FixedArray::kHeaderSize; CopyWords(reinterpret_cast<Object**>(to_address) + to_start, reinterpret_cast<Object**>(from_address) + from_start, copy_size); - if (from_kind == FAST_ELEMENTS && to_kind == FAST_ELEMENTS) { + if (IsFastObjectElementsKind(from_kind) && + IsFastObjectElementsKind(to_kind)) { Heap* heap = from->GetHeap(); if (!heap->InNewSpace(to)) { heap->RecordWrites(to->address(), @@ -190,7 +206,7 @@ static void CopyDictionaryToObjectElements(SeededNumberDictionary* from, raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); copy_size = from->max_number_key() + 1 - from_start; #ifdef DEBUG - // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already + // Fast object arrays cannot be uninitialized. Ensure they are already // marked with the hole. if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { for (int i = to_start + copy_size; i < to->length(); ++i) { @@ -200,7 +216,7 @@ static void CopyDictionaryToObjectElements(SeededNumberDictionary* from, #endif } ASSERT(to != from); - ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS); + ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); if (copy_size == 0) return; uint32_t to_length = to->length(); if (to_start + copy_size > to_length) { @@ -216,7 +232,7 @@ static void CopyDictionaryToObjectElements(SeededNumberDictionary* from, to->set_the_hole(i + to_start); } } - if (to_kind == FAST_ELEMENTS) { + if (IsFastObjectElementsKind(to_kind)) { if (!heap->InNewSpace(to)) { heap->RecordWrites(to->address(), to->OffsetOfElementAt(to_start), @@ -234,7 +250,7 @@ MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements( ElementsKind to_kind, uint32_t to_start, int raw_copy_size) { - ASSERT(to_kind == FAST_ELEMENTS || to_kind == FAST_SMI_ONLY_ELEMENTS); + ASSERT(IsFastSmiOrObjectElementsKind(to_kind)); int copy_size = raw_copy_size; if (raw_copy_size < 0) { ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || @@ -242,7 +258,7 @@ MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements( copy_size = Min(from->length() - from_start, to->length() - to_start); #ifdef DEBUG - // FAST_ELEMENT arrays cannot be uninitialized. Ensure they are already + // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already // marked with the hole. if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { for (int i = to_start + copy_size; i < to->length(); ++i) { @@ -255,14 +271,14 @@ MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements( (copy_size + static_cast<int>(from_start)) <= from->length()); if (copy_size == 0) return from; for (int i = 0; i < copy_size; ++i) { - if (to_kind == FAST_SMI_ONLY_ELEMENTS) { + if (IsFastSmiElementsKind(to_kind)) { UNIMPLEMENTED(); return Failure::Exception(); } else { MaybeObject* maybe_value = from->get(i + from_start); Object* value; - ASSERT(to_kind == FAST_ELEMENTS); - // Because FAST_DOUBLE_ELEMENTS -> FAST_ELEMENT allocate HeapObjects + ASSERT(IsFastObjectElementsKind(to_kind)); + // Because Double -> Object elements transitions allocate HeapObjects // iteratively, the allocate must succeed within a single GC cycle, // otherwise the retry after the GC will also fail. In order to ensure // that no GC is triggered, allocate HeapNumbers from old space if they @@ -313,6 +329,76 @@ static void CopyDoubleToDoubleElements(FixedDoubleArray* from, } +static void CopySmiToDoubleElements(FixedArray* from, + uint32_t from_start, + FixedDoubleArray* to, + uint32_t to_start, + int raw_copy_size) { + int copy_size = raw_copy_size; + if (raw_copy_size < 0) { + ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || + raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + copy_size = from->length() - from_start; + if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { + for (int i = to_start + copy_size; i < to->length(); ++i) { + to->set_the_hole(i); + } + } + } + ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && + (copy_size + static_cast<int>(from_start)) <= from->length()); + if (copy_size == 0) return; + Object* the_hole = from->GetHeap()->the_hole_value(); + for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size); + from_start < from_end; from_start++, to_start++) { + Object* hole_or_smi = from->get(from_start); + if (hole_or_smi == the_hole) { + to->set_the_hole(to_start); + } else { + to->set(to_start, Smi::cast(hole_or_smi)->value()); + } + } +} + + +static void CopyPackedSmiToDoubleElements(FixedArray* from, + uint32_t from_start, + FixedDoubleArray* to, + uint32_t to_start, + int packed_size, + int raw_copy_size) { + int copy_size = raw_copy_size; + uint32_t to_end; + if (raw_copy_size < 0) { + ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd || + raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole); + copy_size = from->length() - from_start; + if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) { + to_end = to->length(); + } else { + to_end = to_start + static_cast<uint32_t>(copy_size); + } + } else { + to_end = to_start + static_cast<uint32_t>(copy_size); + } + ASSERT(static_cast<int>(to_end) <= to->length()); + ASSERT(packed_size >= 0 && packed_size <= copy_size); + ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && + (copy_size + static_cast<int>(from_start)) <= from->length()); + if (copy_size == 0) return; + for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size); + from_start < from_end; from_start++, to_start++) { + Object* smi = from->get(from_start); + ASSERT(!smi->IsTheHole()); + to->set(to_start, Smi::cast(smi)->value()); + } + + while (to_start < to_end) { + to->set_the_hole(to_start++); + } +} + + static void CopyObjectToDoubleElements(FixedArray* from, uint32_t from_start, FixedDoubleArray* to, @@ -332,12 +418,14 @@ static void CopyObjectToDoubleElements(FixedArray* from, ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() && (copy_size + static_cast<int>(from_start)) <= from->length()); if (copy_size == 0) return; - for (int i = 0; i < copy_size; i++) { - Object* hole_or_object = from->get(i + from_start); - if (hole_or_object->IsTheHole()) { - to->set_the_hole(i + to_start); + Object* the_hole = from->GetHeap()->the_hole_value(); + for (uint32_t from_end = from_start + copy_size; + from_start < from_end; from_start++, to_start++) { + Object* hole_or_object = from->get(from_start); + if (hole_or_object == the_hole) { + to->set_the_hole(to_start); } else { - to->set(i + to_start, hole_or_object->Number()); + to->set(to_start, hole_or_object->Number()); } } } @@ -404,13 +492,44 @@ class ElementsAccessorBase : public ElementsAccessor { virtual ElementsKind kind() const { return ElementsTraits::Kind; } + static void ValidateContents(JSObject* holder, int length) { + } + + static void ValidateImpl(JSObject* holder) { + FixedArrayBase* fixed_array_base = holder->elements(); + // When objects are first allocated, its elements are Failures. + if (fixed_array_base->IsFailure()) return; + if (!fixed_array_base->IsHeapObject()) return; + Map* map = fixed_array_base->map(); + // Arrays that have been shifted in place can't be verified. + Heap* heap = holder->GetHeap(); + if (map == heap->one_pointer_filler_map() || + map == heap->two_pointer_filler_map() || + map == heap->free_space_map()) { + return; + } + int length = 0; + if (holder->IsJSArray()) { + Object* length_obj = JSArray::cast(holder)->length(); + if (length_obj->IsSmi()) { + length = Smi::cast(length_obj)->value(); + } + } else { + length = fixed_array_base->length(); + } + ElementsAccessorSubclass::ValidateContents(holder, length); + } + + virtual void Validate(JSObject* holder) { + ElementsAccessorSubclass::ValidateImpl(holder); + } + static bool HasElementImpl(Object* receiver, JSObject* holder, uint32_t key, BackingStore* backing_store) { - MaybeObject* element = - ElementsAccessorSubclass::GetImpl(receiver, holder, key, backing_store); - return !element->IsTheHole(); + return ElementsAccessorSubclass::GetAttributesImpl( + receiver, holder, key, backing_store) != ABSENT; } virtual bool HasElement(Object* receiver, @@ -444,6 +563,29 @@ class ElementsAccessorBase : public ElementsAccessor { : backing_store->GetHeap()->the_hole_value(); } + MUST_USE_RESULT virtual PropertyAttributes GetAttributes( + Object* receiver, + JSObject* holder, + uint32_t key, + FixedArrayBase* backing_store) { + if (backing_store == NULL) { + backing_store = holder->elements(); + } + return ElementsAccessorSubclass::GetAttributesImpl( + receiver, holder, key, BackingStore::cast(backing_store)); + } + + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + BackingStore* backing_store) { + if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) { + return ABSENT; + } + return backing_store->is_the_hole(key) ? ABSENT : NONE; + } + MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array, Object* length) { return ElementsAccessorSubclass::SetLengthImpl( @@ -455,9 +597,10 @@ class ElementsAccessorBase : public ElementsAccessor { Object* length, BackingStore* backing_store); - MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(JSArray* array, - int capacity, - int length) { + MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength( + JSArray* array, + int capacity, + int length) { return ElementsAccessorSubclass::SetFastElementsCapacityAndLength( array, capacity, @@ -481,6 +624,7 @@ class ElementsAccessorBase : public ElementsAccessor { FixedArrayBase* to, ElementsKind to_kind, uint32_t to_start, + int packed_size, int copy_size) { UNREACHABLE(); return NULL; @@ -493,14 +637,27 @@ class ElementsAccessorBase : public ElementsAccessor { uint32_t to_start, int copy_size, FixedArrayBase* from) { + int packed_size = kPackedSizeNotKnown; if (from == NULL) { from = from_holder->elements(); } + + if (from_holder) { + ElementsKind elements_kind = from_holder->GetElementsKind(); + bool is_packed = IsFastPackedElementsKind(elements_kind) && + from_holder->IsJSArray(); + if (is_packed) { + packed_size = Smi::cast(JSArray::cast(from_holder)->length())->value(); + if (copy_size >= 0 && packed_size > copy_size) { + packed_size = copy_size; + } + } + } if (from->length() == 0) { return from; } return ElementsAccessorSubclass::CopyElementsImpl( - from, from_start, to, to_kind, to_start, copy_size); + from, from_start, to, to_kind, to_start, packed_size, copy_size); } MUST_USE_RESULT virtual MaybeObject* AddElementsToFixedArray( @@ -623,6 +780,7 @@ class FastElementsAccessor KindTraits>(name) {} protected: friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>; + friend class NonStrictArgumentsElementsAccessor; typedef typename KindTraits::BackingStore BackingStore; @@ -633,10 +791,21 @@ class FastElementsAccessor Object* length_object, uint32_t length) { uint32_t old_capacity = backing_store->length(); + Object* old_length = array->length(); + bool same_or_smaller_size = old_length->IsSmi() && + static_cast<uint32_t>(Smi::cast(old_length)->value()) >= length; + ElementsKind kind = array->GetElementsKind(); + + if (!same_or_smaller_size && IsFastElementsKind(kind) && + !IsFastHoleyElementsKind(kind)) { + kind = GetHoleyElementsKind(kind); + MaybeObject* maybe_obj = array->TransitionElementsKind(kind); + if (maybe_obj->IsFailure()) return maybe_obj; + } // Check whether the backing store should be shrunk. if (length <= old_capacity) { - if (array->HasFastTypeElements()) { + if (array->HasFastSmiOrObjectElements()) { MaybeObject* maybe_obj = array->EnsureWritableFastElements(); if (!maybe_obj->To(&backing_store)) return maybe_obj; } @@ -653,7 +822,7 @@ class FastElementsAccessor } } else { // Otherwise, fill the unused tail with holes. - int old_length = FastD2I(array->length()->Number()); + int old_length = FastD2IChecked(array->length()->Number()); for (int i = length; i < old_length; i++) { backing_store->set_the_hole(i); } @@ -668,59 +837,66 @@ class FastElementsAccessor MaybeObject* result = FastElementsAccessorSubclass:: SetFastElementsCapacityAndLength(array, new_capacity, length); if (result->IsFailure()) return result; + array->ValidateElements(); return length_object; } // Request conversion to slow elements. return array->GetHeap()->undefined_value(); } -}; - - -class FastObjectElementsAccessor - : public FastElementsAccessor<FastObjectElementsAccessor, - ElementsKindTraits<FAST_ELEMENTS>, - kPointerSize> { - public: - explicit FastObjectElementsAccessor(const char* name) - : FastElementsAccessor<FastObjectElementsAccessor, - ElementsKindTraits<FAST_ELEMENTS>, - kPointerSize>(name) {} static MaybeObject* DeleteCommon(JSObject* obj, - uint32_t key) { - ASSERT(obj->HasFastElements() || - obj->HasFastSmiOnlyElements() || + uint32_t key, + JSReceiver::DeleteMode mode) { + ASSERT(obj->HasFastSmiOrObjectElements() || + obj->HasFastDoubleElements() || obj->HasFastArgumentsElements()); Heap* heap = obj->GetHeap(); - FixedArray* backing_store = FixedArray::cast(obj->elements()); - if (backing_store->map() == heap->non_strict_arguments_elements_map()) { - backing_store = FixedArray::cast(backing_store->get(1)); - } else { - Object* writable; - MaybeObject* maybe = obj->EnsureWritableFastElements(); - if (!maybe->ToObject(&writable)) return maybe; - backing_store = FixedArray::cast(writable); + Object* elements = obj->elements(); + if (elements == heap->empty_fixed_array()) { + return heap->true_value(); + } + typename KindTraits::BackingStore* backing_store = + KindTraits::BackingStore::cast(elements); + bool is_non_strict_arguments_elements_map = + backing_store->map() == heap->non_strict_arguments_elements_map(); + if (is_non_strict_arguments_elements_map) { + backing_store = + KindTraits::BackingStore::cast( + FixedArray::cast(backing_store)->get(1)); } uint32_t length = static_cast<uint32_t>( obj->IsJSArray() ? Smi::cast(JSArray::cast(obj)->length())->value() : backing_store->length()); if (key < length) { + if (!is_non_strict_arguments_elements_map) { + ElementsKind kind = KindTraits::Kind; + if (IsFastPackedElementsKind(kind)) { + MaybeObject* transitioned = + obj->TransitionElementsKind(GetHoleyElementsKind(kind)); + if (transitioned->IsFailure()) return transitioned; + } + if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) { + Object* writable; + MaybeObject* maybe = obj->EnsureWritableFastElements(); + if (!maybe->ToObject(&writable)) return maybe; + backing_store = KindTraits::BackingStore::cast(writable); + } + } backing_store->set_the_hole(key); // If an old space backing store is larger than a certain size and // has too few used values, normalize it. // To avoid doing the check on every delete we require at least // one adjacent hole to the value being deleted. - Object* hole = heap->the_hole_value(); const int kMinLengthForSparsenessCheck = 64; if (backing_store->length() >= kMinLengthForSparsenessCheck && !heap->InNewSpace(backing_store) && - ((key > 0 && backing_store->get(key - 1) == hole) || - (key + 1 < length && backing_store->get(key + 1) == hole))) { + ((key > 0 && backing_store->is_the_hole(key - 1)) || + (key + 1 < length && backing_store->is_the_hole(key + 1)))) { int num_used = 0; for (int i = 0; i < backing_store->length(); ++i) { - if (backing_store->get(i) != hole) ++num_used; + if (!backing_store->is_the_hole(i)) ++num_used; // Bail out early if more than 1/4 is used. if (4 * num_used > backing_store->length()) break; } @@ -733,27 +909,90 @@ class FastObjectElementsAccessor return heap->true_value(); } + virtual MaybeObject* Delete(JSObject* obj, + uint32_t key, + JSReceiver::DeleteMode mode) { + return DeleteCommon(obj, key, mode); + } + + static bool HasElementImpl( + Object* receiver, + JSObject* holder, + uint32_t key, + typename KindTraits::BackingStore* backing_store) { + if (key >= static_cast<uint32_t>(backing_store->length())) { + return false; + } + return !backing_store->is_the_hole(key); + } + + static void ValidateContents(JSObject* holder, int length) { +#if DEBUG + FixedArrayBase* elements = holder->elements(); + Heap* heap = elements->GetHeap(); + Map* map = elements->map(); + ASSERT((IsFastSmiOrObjectElementsKind(KindTraits::Kind) && + (map == heap->fixed_array_map() || + map == heap->fixed_cow_array_map())) || + (IsFastDoubleElementsKind(KindTraits::Kind) == + ((map == heap->fixed_array_map() && length == 0) || + map == heap->fixed_double_array_map()))); + for (int i = 0; i < length; i++) { + typename KindTraits::BackingStore* backing_store = + KindTraits::BackingStore::cast(elements); + ASSERT((!IsFastSmiElementsKind(KindTraits::Kind) || + static_cast<Object*>(backing_store->get(i))->IsSmi()) || + (IsFastHoleyElementsKind(KindTraits::Kind) == + backing_store->is_the_hole(i))); + } +#endif + } +}; + + +template<typename FastElementsAccessorSubclass, + typename KindTraits> +class FastSmiOrObjectElementsAccessor + : public FastElementsAccessor<FastElementsAccessorSubclass, + KindTraits, + kPointerSize> { + public: + explicit FastSmiOrObjectElementsAccessor(const char* name) + : FastElementsAccessor<FastElementsAccessorSubclass, + KindTraits, + kPointerSize>(name) {} + static MaybeObject* CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, FixedArrayBase* to, ElementsKind to_kind, uint32_t to_start, + int packed_size, int copy_size) { - switch (to_kind) { - case FAST_SMI_ONLY_ELEMENTS: - case FAST_ELEMENTS: { - CopyObjectToObjectElements( - FixedArray::cast(from), ElementsTraits::Kind, from_start, - FixedArray::cast(to), to_kind, to_start, copy_size); - return from; - } - case FAST_DOUBLE_ELEMENTS: + if (IsFastSmiOrObjectElementsKind(to_kind)) { + CopyObjectToObjectElements( + FixedArray::cast(from), KindTraits::Kind, from_start, + FixedArray::cast(to), to_kind, to_start, copy_size); + } else if (IsFastDoubleElementsKind(to_kind)) { + if (IsFastSmiElementsKind(KindTraits::Kind)) { + if (IsFastPackedElementsKind(KindTraits::Kind) && + packed_size != kPackedSizeNotKnown) { + CopyPackedSmiToDoubleElements( + FixedArray::cast(from), from_start, + FixedDoubleArray::cast(to), to_start, + packed_size, copy_size); + } else { + CopySmiToDoubleElements( + FixedArray::cast(from), from_start, + FixedDoubleArray::cast(to), to_start, copy_size); + } + } else { CopyObjectToDoubleElements( FixedArray::cast(from), from_start, FixedDoubleArray::cast(to), to_start, copy_size); - return from; - default: - UNREACHABLE(); + } + } else { + UNREACHABLE(); } return to->GetHeap()->undefined_value(); } @@ -762,64 +1001,102 @@ class FastObjectElementsAccessor static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj, uint32_t capacity, uint32_t length) { - JSObject::SetFastElementsCapacityMode set_capacity_mode = - obj->HasFastSmiOnlyElements() - ? JSObject::kAllowSmiOnlyElements - : JSObject::kDontAllowSmiOnlyElements; + JSObject::SetFastElementsCapacitySmiMode set_capacity_mode = + obj->HasFastSmiElements() + ? JSObject::kAllowSmiElements + : JSObject::kDontAllowSmiElements; return obj->SetFastElementsCapacityAndLength(capacity, length, set_capacity_mode); } +}; - protected: - friend class FastElementsAccessor<FastObjectElementsAccessor, - ElementsKindTraits<FAST_ELEMENTS>, - kPointerSize>; - virtual MaybeObject* Delete(JSObject* obj, - uint32_t key, - JSReceiver::DeleteMode mode) { - return DeleteCommon(obj, key); - } +class FastPackedSmiElementsAccessor + : public FastSmiOrObjectElementsAccessor< + FastPackedSmiElementsAccessor, + ElementsKindTraits<FAST_SMI_ELEMENTS> > { + public: + explicit FastPackedSmiElementsAccessor(const char* name) + : FastSmiOrObjectElementsAccessor< + FastPackedSmiElementsAccessor, + ElementsKindTraits<FAST_SMI_ELEMENTS> >(name) {} +}; + + +class FastHoleySmiElementsAccessor + : public FastSmiOrObjectElementsAccessor< + FastHoleySmiElementsAccessor, + ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> > { + public: + explicit FastHoleySmiElementsAccessor(const char* name) + : FastSmiOrObjectElementsAccessor< + FastHoleySmiElementsAccessor, + ElementsKindTraits<FAST_HOLEY_SMI_ELEMENTS> >(name) {} +}; + + +class FastPackedObjectElementsAccessor + : public FastSmiOrObjectElementsAccessor< + FastPackedObjectElementsAccessor, + ElementsKindTraits<FAST_ELEMENTS> > { + public: + explicit FastPackedObjectElementsAccessor(const char* name) + : FastSmiOrObjectElementsAccessor< + FastPackedObjectElementsAccessor, + ElementsKindTraits<FAST_ELEMENTS> >(name) {} +}; + + +class FastHoleyObjectElementsAccessor + : public FastSmiOrObjectElementsAccessor< + FastHoleyObjectElementsAccessor, + ElementsKindTraits<FAST_HOLEY_ELEMENTS> > { + public: + explicit FastHoleyObjectElementsAccessor(const char* name) + : FastSmiOrObjectElementsAccessor< + FastHoleyObjectElementsAccessor, + ElementsKindTraits<FAST_HOLEY_ELEMENTS> >(name) {} }; +template<typename FastElementsAccessorSubclass, + typename KindTraits> class FastDoubleElementsAccessor - : public FastElementsAccessor<FastDoubleElementsAccessor, - ElementsKindTraits<FAST_DOUBLE_ELEMENTS>, + : public FastElementsAccessor<FastElementsAccessorSubclass, + KindTraits, kDoubleSize> { public: explicit FastDoubleElementsAccessor(const char* name) - : FastElementsAccessor<FastDoubleElementsAccessor, - ElementsKindTraits<FAST_DOUBLE_ELEMENTS>, + : FastElementsAccessor<FastElementsAccessorSubclass, + KindTraits, kDoubleSize>(name) {} static MaybeObject* SetFastElementsCapacityAndLength(JSObject* obj, uint32_t capacity, uint32_t length) { - return obj->SetFastDoubleElementsCapacityAndLength(capacity, length); + return obj->SetFastDoubleElementsCapacityAndLength(capacity, + length); } protected: - friend class ElementsAccessorBase<FastDoubleElementsAccessor, - ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >; - friend class FastElementsAccessor<FastDoubleElementsAccessor, - ElementsKindTraits<FAST_DOUBLE_ELEMENTS>, - kDoubleSize>; - static MaybeObject* CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, FixedArrayBase* to, ElementsKind to_kind, uint32_t to_start, + int packed_size, int copy_size) { switch (to_kind) { - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_ELEMENTS: return CopyDoubleToObjectElements( FixedDoubleArray::cast(from), from_start, FixedArray::cast(to), to_kind, to_start, copy_size); case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: CopyDoubleToDoubleElements(FixedDoubleArray::cast(from), from_start, FixedDoubleArray::cast(to), to_start, copy_size); @@ -829,26 +1106,35 @@ class FastDoubleElementsAccessor } return to->GetHeap()->undefined_value(); } +}; - virtual MaybeObject* Delete(JSObject* obj, - uint32_t key, - JSReceiver::DeleteMode mode) { - int length = obj->IsJSArray() - ? Smi::cast(JSArray::cast(obj)->length())->value() - : FixedDoubleArray::cast(obj->elements())->length(); - if (key < static_cast<uint32_t>(length)) { - FixedDoubleArray::cast(obj->elements())->set_the_hole(key); - } - return obj->GetHeap()->true_value(); - } - static bool HasElementImpl(Object* receiver, - JSObject* holder, - uint32_t key, - FixedDoubleArray* backing_store) { - return key < static_cast<uint32_t>(backing_store->length()) && - !backing_store->is_the_hole(key); - } +class FastPackedDoubleElementsAccessor + : public FastDoubleElementsAccessor< + FastPackedDoubleElementsAccessor, + ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > { + public: + friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor, + ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >; + explicit FastPackedDoubleElementsAccessor(const char* name) + : FastDoubleElementsAccessor< + FastPackedDoubleElementsAccessor, + ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >(name) {} +}; + + +class FastHoleyDoubleElementsAccessor + : public FastDoubleElementsAccessor< + FastHoleyDoubleElementsAccessor, + ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > { + public: + friend class ElementsAccessorBase< + FastHoleyDoubleElementsAccessor, + ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >; + explicit FastHoleyDoubleElementsAccessor(const char* name) + : FastDoubleElementsAccessor< + FastHoleyDoubleElementsAccessor, + ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >(name) {} }; @@ -879,6 +1165,16 @@ class ExternalElementsAccessor : backing_store->GetHeap()->undefined_value(); } + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + BackingStore* backing_store) { + return + key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store) + ? NONE : ABSENT; + } + MUST_USE_RESULT static MaybeObject* SetLengthImpl( JSObject* obj, Object* length, @@ -1011,7 +1307,30 @@ class DictionaryElementsAccessor JSArray* array, Object* length_object, uint32_t length) { - if (length == 0) { + Heap* heap = array->GetHeap(); + int capacity = dict->Capacity(); + uint32_t new_length = length; + uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); + if (new_length < old_length) { + // Find last non-deletable element in range of elements to be + // deleted and adjust range accordingly. + for (int i = 0; i < capacity; i++) { + Object* key = dict->KeyAt(i); + if (key->IsNumber()) { + uint32_t number = static_cast<uint32_t>(key->Number()); + if (new_length <= number && number < old_length) { + PropertyDetails details = dict->DetailsAt(i); + if (details.IsDontDelete()) new_length = number + 1; + } + } + } + if (new_length != length) { + MaybeObject* maybe_object = heap->NumberFromUint32(new_length); + if (!maybe_object->To(&length_object)) return maybe_object; + } + } + + if (new_length == 0) { // If the length of a slow array is reset to zero, we clear // the array and flush backing storage. This has the added // benefit that the array returns to fast mode. @@ -1019,45 +1338,22 @@ class DictionaryElementsAccessor MaybeObject* maybe_obj = array->ResetElements(); if (!maybe_obj->ToObject(&obj)) return maybe_obj; } else { - uint32_t new_length = length; - uint32_t old_length = static_cast<uint32_t>(array->length()->Number()); - if (new_length < old_length) { - // Find last non-deletable element in range of elements to be - // deleted and adjust range accordingly. - Heap* heap = array->GetHeap(); - int capacity = dict->Capacity(); - for (int i = 0; i < capacity; i++) { - Object* key = dict->KeyAt(i); - if (key->IsNumber()) { - uint32_t number = static_cast<uint32_t>(key->Number()); - if (new_length <= number && number < old_length) { - PropertyDetails details = dict->DetailsAt(i); - if (details.IsDontDelete()) new_length = number + 1; - } + // Remove elements that should be deleted. + int removed_entries = 0; + Object* the_hole_value = heap->the_hole_value(); + for (int i = 0; i < capacity; i++) { + Object* key = dict->KeyAt(i); + if (key->IsNumber()) { + uint32_t number = static_cast<uint32_t>(key->Number()); + if (new_length <= number && number < old_length) { + dict->SetEntry(i, the_hole_value, the_hole_value); + removed_entries++; } } - if (new_length != length) { - MaybeObject* maybe_object = heap->NumberFromUint32(new_length); - if (!maybe_object->To(&length_object)) return maybe_object; - } - - // Remove elements that should be deleted. - int removed_entries = 0; - Object* the_hole_value = heap->the_hole_value(); - for (int i = 0; i < capacity; i++) { - Object* key = dict->KeyAt(i); - if (key->IsNumber()) { - uint32_t number = static_cast<uint32_t>(key->Number()); - if (new_length <= number && number < old_length) { - dict->SetEntry(i, the_hole_value, the_hole_value); - removed_entries++; - } - } - } - - // Update the number of elements. - dict->ElementsRemoved(removed_entries); } + + // Update the number of elements. + dict->ElementsRemoved(removed_entries); } return length_object; } @@ -1112,15 +1408,19 @@ class DictionaryElementsAccessor FixedArrayBase* to, ElementsKind to_kind, uint32_t to_start, + int packed_size, int copy_size) { switch (to_kind) { - case FAST_SMI_ONLY_ELEMENTS: + case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: + case FAST_HOLEY_SMI_ELEMENTS: + case FAST_HOLEY_ELEMENTS: CopyDictionaryToObjectElements( SeededNumberDictionary::cast(from), from_start, FixedArray::cast(to), to_kind, to_start, copy_size); return from; case FAST_DOUBLE_ELEMENTS: + case FAST_HOLEY_DOUBLE_ELEMENTS: CopyDictionaryToDoubleElements( SeededNumberDictionary::cast(from), from_start, FixedDoubleArray::cast(to), to_start, copy_size); @@ -1163,6 +1463,18 @@ class DictionaryElementsAccessor return obj->GetHeap()->the_hole_value(); } + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + SeededNumberDictionary* backing_store) { + int entry = backing_store->FindEntry(key); + if (entry != SeededNumberDictionary::kNotFound) { + return backing_store->DetailsAt(entry).attributes(); + } + return ABSENT; + } + static bool HasElementImpl(Object* receiver, JSObject* holder, uint32_t key, @@ -1222,6 +1534,22 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< } } + MUST_USE_RESULT static PropertyAttributes GetAttributesImpl( + Object* receiver, + JSObject* obj, + uint32_t key, + FixedArray* parameter_map) { + Object* probe = GetParameterMapArg(obj, parameter_map, key); + if (!probe->IsTheHole()) { + return NONE; + } else { + // If not aliased, check the arguments. + FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); + return ElementsAccessor::ForArray(arguments)->GetAttributes( + receiver, obj, key, arguments); + } + } + MUST_USE_RESULT static MaybeObject* SetLengthImpl( JSObject* obj, Object* length, @@ -1247,7 +1575,10 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< if (arguments->IsDictionary()) { return DictionaryElementsAccessor::DeleteCommon(obj, key, mode); } else { - return FastObjectElementsAccessor::DeleteCommon(obj, key); + // It's difficult to access the version of DeleteCommon that is declared + // in the templatized super class, call the concrete implementation in + // the class for the most generalized ElementsKind subclass. + return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode); } } return obj->GetHeap()->true_value(); @@ -1258,6 +1589,7 @@ class NonStrictArgumentsElementsAccessor : public ElementsAccessorBase< FixedArrayBase* to, ElementsKind to_kind, uint32_t to_start, + int packed_size, int copy_size) { FixedArray* parameter_map = FixedArray::cast(from); FixedArray* arguments = FixedArray::cast(parameter_map->get(1)); @@ -1311,7 +1643,7 @@ ElementsAccessor* ElementsAccessor::ForArray(FixedArrayBase* array) { if (array->IsDictionary()) { return elements_accessors_[DICTIONARY_ELEMENTS]; } else { - return elements_accessors_[FAST_ELEMENTS]; + return elements_accessors_[FAST_HOLEY_ELEMENTS]; } case EXTERNAL_BYTE_ARRAY_TYPE: return elements_accessors_[EXTERNAL_BYTE_ELEMENTS]; |