diff options
Diffstat (limited to 'deps/v8/src/elements.cc')
-rw-r--r-- | deps/v8/src/elements.cc | 724 |
1 files changed, 521 insertions, 203 deletions
diff --git a/deps/v8/src/elements.cc b/deps/v8/src/elements.cc index 9fd450a75a..288c60e305 100644 --- a/deps/v8/src/elements.cc +++ b/deps/v8/src/elements.cc @@ -7,6 +7,7 @@ #include "src/arguments.h" #include "src/conversions.h" #include "src/factory.h" +#include "src/isolate-inl.h" #include "src/messages.h" #include "src/objects-inl.h" #include "src/utils.h" @@ -428,7 +429,6 @@ static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base, } } - static void TraceTopFrame(Isolate* isolate) { StackFrameIterator it(isolate); if (it.done()) { @@ -503,12 +503,6 @@ class ElementsAccessorBase : public ElementsAccessor { ElementsAccessorSubclass::ValidateImpl(holder); } - bool IsPacked(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store, - uint32_t start, uint32_t end) final { - return ElementsAccessorSubclass::IsPackedImpl(holder, backing_store, start, - end); - } - static bool IsPackedImpl(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store, uint32_t start, uint32_t end) { @@ -608,81 +602,67 @@ class ElementsAccessorBase : public ElementsAccessor { UNREACHABLE(); } - uint32_t Push(Handle<JSArray> receiver, Handle<FixedArrayBase> backing_store, - Arguments* args, uint32_t push_size) final { - return ElementsAccessorSubclass::PushImpl(receiver, backing_store, args, - push_size); + uint32_t Push(Handle<JSArray> receiver, Arguments* args, + uint32_t push_size) final { + return ElementsAccessorSubclass::PushImpl(receiver, args, push_size); } - static uint32_t PushImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> elms_obj, Arguments* args, + static uint32_t PushImpl(Handle<JSArray> receiver, Arguments* args, uint32_t push_sized) { UNREACHABLE(); return 0; } - uint32_t Unshift(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, Arguments* args, + uint32_t Unshift(Handle<JSArray> receiver, Arguments* args, uint32_t unshift_size) final { - return ElementsAccessorSubclass::UnshiftImpl(receiver, backing_store, args, - unshift_size); + return ElementsAccessorSubclass::UnshiftImpl(receiver, args, unshift_size); } - static uint32_t UnshiftImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> elms_obj, Arguments* args, + static uint32_t UnshiftImpl(Handle<JSArray> receiver, Arguments* args, uint32_t unshift_size) { UNREACHABLE(); return 0; } - Handle<JSArray> Slice(Handle<JSObject> receiver, - Handle<FixedArrayBase> backing_store, uint32_t start, + Handle<JSArray> Slice(Handle<JSObject> receiver, uint32_t start, uint32_t end) final { - return ElementsAccessorSubclass::SliceImpl(receiver, backing_store, start, - end); + return ElementsAccessorSubclass::SliceImpl(receiver, start, end); } static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, - Handle<FixedArrayBase> backing_store, uint32_t start, uint32_t end) { UNREACHABLE(); return Handle<JSArray>(); } - Handle<JSArray> Splice(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, uint32_t start, + Handle<JSArray> Splice(Handle<JSArray> receiver, uint32_t start, uint32_t delete_count, Arguments* args, uint32_t add_count) final { - return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start, - delete_count, args, add_count); + return ElementsAccessorSubclass::SpliceImpl(receiver, start, delete_count, + args, add_count); } static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, uint32_t start, uint32_t delete_count, Arguments* args, uint32_t add_count) { UNREACHABLE(); return Handle<JSArray>(); } - Handle<Object> Pop(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store) final { - return ElementsAccessorSubclass::PopImpl(receiver, backing_store); + Handle<Object> Pop(Handle<JSArray> receiver) final { + return ElementsAccessorSubclass::PopImpl(receiver); } - static Handle<Object> PopImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store) { + static Handle<Object> PopImpl(Handle<JSArray> receiver) { UNREACHABLE(); return Handle<Object>(); } - Handle<Object> Shift(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store) final { - return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store); + Handle<Object> Shift(Handle<JSArray> receiver) final { + return ElementsAccessorSubclass::ShiftImpl(receiver); } - static Handle<Object> ShiftImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store) { + static Handle<Object> ShiftImpl(Handle<JSArray> receiver) { UNREACHABLE(); return Handle<Object>(); } @@ -714,8 +694,11 @@ class ElementsAccessorBase : public ElementsAccessor { if (length == 0) { array->initialize_elements(); } else if (length <= capacity) { - if (array->HasFastSmiOrObjectElements()) { - backing_store = JSObject::EnsureWritableFastElements(array); + if (IsFastSmiOrObjectElementsKind(kind())) { + JSObject::EnsureWritableFastElements(array); + if (array->elements() != *backing_store) { + backing_store = handle(array->elements(), isolate); + } } if (2 * length <= capacity) { // If more than half the elements won't be used, trim the array. @@ -737,6 +720,16 @@ class ElementsAccessorBase : public ElementsAccessor { JSObject::ValidateElements(array); } + static uint32_t GetIterationLength(JSObject* receiver, + FixedArrayBase* elements) { + if (receiver->IsJSArray()) { + DCHECK(JSArray::cast(receiver)->length()->IsSmi()); + return static_cast<uint32_t>( + Smi::cast(JSArray::cast(receiver)->length())->value()); + } + return ElementsAccessorSubclass::GetCapacityImpl(receiver, elements); + } + static Handle<FixedArrayBase> ConvertElementsWithCapacity( Handle<JSObject> object, Handle<FixedArrayBase> old_elements, ElementsKind from_kind, uint32_t capacity) { @@ -853,40 +846,194 @@ class ElementsAccessorBase : public ElementsAccessor { from, from_start, *to, from_kind, to_start, packed_size, copy_size); } + Handle<SeededNumberDictionary> Normalize(Handle<JSObject> object) final { + return ElementsAccessorSubclass::NormalizeImpl(object, + handle(object->elements())); + } + + static Handle<SeededNumberDictionary> NormalizeImpl( + Handle<JSObject> object, Handle<FixedArrayBase> elements) { + UNREACHABLE(); + return Handle<SeededNumberDictionary>(); + } + + Maybe<bool> CollectValuesOrEntries(Isolate* isolate, Handle<JSObject> object, + Handle<FixedArray> values_or_entries, + bool get_entries, int* nof_items, + PropertyFilter filter) { + return ElementsAccessorSubclass::CollectValuesOrEntriesImpl( + isolate, object, values_or_entries, get_entries, nof_items, filter); + } + + static Maybe<bool> CollectValuesOrEntriesImpl( + Isolate* isolate, Handle<JSObject> object, + Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, + PropertyFilter filter) { + int count = 0; + KeyAccumulator accumulator(isolate, OWN_ONLY, ALL_PROPERTIES); + accumulator.NextPrototype(); + ElementsAccessorSubclass::CollectElementIndicesImpl( + object, handle(object->elements(), isolate), &accumulator, kMaxUInt32, + ALL_PROPERTIES, 0); + Handle<FixedArray> keys = accumulator.GetKeys(); + + for (int i = 0; i < keys->length(); ++i) { + Handle<Object> key(keys->get(i), isolate); + Handle<Object> value; + uint32_t index; + if (!key->ToUint32(&index)) continue; + + uint32_t entry = ElementsAccessorSubclass::GetEntryForIndexImpl( + *object, object->elements(), index, filter); + if (entry == kMaxUInt32) continue; + + PropertyDetails details = + ElementsAccessorSubclass::GetDetailsImpl(*object, entry); + + if (details.kind() == kData) { + value = ElementsAccessorSubclass::GetImpl(object, entry); + } else { + LookupIterator it(isolate, object, index, LookupIterator::OWN); + ASSIGN_RETURN_ON_EXCEPTION_VALUE( + isolate, value, Object::GetProperty(&it), Nothing<bool>()); + } + if (get_entries) { + value = MakeEntryPair(isolate, index, value); + } + values_or_entries->set(count++, *value); + } + + *nof_items = count; + return Just(true); + } + + void CollectElementIndices(Handle<JSObject> object, + Handle<FixedArrayBase> backing_store, + KeyAccumulator* keys, uint32_t range, + PropertyFilter filter, uint32_t offset) final { + if (filter & ONLY_ALL_CAN_READ) return; + ElementsAccessorSubclass::CollectElementIndicesImpl( + object, backing_store, keys, range, filter, offset); + } + static void CollectElementIndicesImpl(Handle<JSObject> object, Handle<FixedArrayBase> backing_store, KeyAccumulator* keys, uint32_t range, PropertyFilter filter, uint32_t offset) { DCHECK_NE(DICTIONARY_ELEMENTS, kind()); - if (filter & ONLY_ALL_CAN_READ) { - // Non-dictionary elements can't have all-can-read accessors. - return; - } - uint32_t length = 0; - if (object->IsJSArray()) { - length = Smi::cast(JSArray::cast(*object)->length())->value(); - } else { - length = - ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store); - } + // Non-dictionary elements can't have all-can-read accessors. + uint32_t length = GetIterationLength(*object, *backing_store); if (range < length) length = range; for (uint32_t i = offset; i < length; i++) { - if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store, - filter)) { - continue; + if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store, + filter)) { + keys->AddKey(i); } - keys->AddKey(i); } } - void CollectElementIndices(Handle<JSObject> object, - Handle<FixedArrayBase> backing_store, - KeyAccumulator* keys, uint32_t range, - PropertyFilter filter, uint32_t offset) final { - ElementsAccessorSubclass::CollectElementIndicesImpl( - object, backing_store, keys, range, filter, offset); - }; + static Handle<FixedArray> DirectCollectElementIndicesImpl( + Isolate* isolate, Handle<JSObject> object, + Handle<FixedArrayBase> backing_store, GetKeysConversion convert, + PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices, + uint32_t insertion_index = 0) { + uint32_t length = + ElementsAccessorSubclass::GetIterationLength(*object, *backing_store); + for (uint32_t i = 0; i < length; i++) { + if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store, + filter)) { + if (convert == CONVERT_TO_STRING) { + Handle<String> index_string = isolate->factory()->Uint32ToString(i); + list->set(insertion_index, *index_string); + } else { + list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER); + } + insertion_index++; + } + } + *nof_indices = insertion_index; + return list; + } + + Handle<FixedArray> PrependElementIndices(Handle<JSObject> object, + Handle<FixedArrayBase> backing_store, + Handle<FixedArray> keys, + GetKeysConversion convert, + PropertyFilter filter) final { + return ElementsAccessorSubclass::PrependElementIndicesImpl( + object, backing_store, keys, convert, filter); + } + + static Handle<FixedArray> PrependElementIndicesImpl( + Handle<JSObject> object, Handle<FixedArrayBase> backing_store, + Handle<FixedArray> keys, GetKeysConversion convert, + PropertyFilter filter) { + Isolate* isolate = object->GetIsolate(); + uint32_t nof_property_keys = keys->length(); + uint32_t initial_list_length = + ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store); + initial_list_length += nof_property_keys; + + // Collect the element indices into a new list. + uint32_t nof_indices = 0; + Handle<FixedArray> combined_keys = + isolate->factory()->NewFixedArray(initial_list_length); + combined_keys = ElementsAccessorSubclass::DirectCollectElementIndicesImpl( + isolate, object, backing_store, convert, filter, combined_keys, + &nof_indices); + + // Sort the indices list if necessary. + if (IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind())) { + struct { + bool operator()(Object* a, Object* b) { + if (!a->IsUndefined()) { + if (b->IsUndefined()) return true; + return a->Number() < b->Number(); + } + return !b->IsUndefined(); + } + } cmp; + Object** start = + reinterpret_cast<Object**>(combined_keys->GetFirstElementAddress()); + std::sort(start, start + nof_indices, cmp); + uint32_t array_length = 0; + // Indices from dictionary elements should only be converted after + // sorting. + if (convert == CONVERT_TO_STRING) { + for (uint32_t i = 0; i < nof_indices; i++) { + Handle<Object> index_string = isolate->factory()->Uint32ToString( + combined_keys->get(i)->Number()); + combined_keys->set(i, *index_string); + } + } else if (!(object->IsJSArray() && + JSArray::cast(*object)->length()->ToArrayLength( + &array_length) && + array_length <= Smi::kMaxValue)) { + // Since we use std::sort above, the GC will no longer know where the + // HeapNumbers are, hence we have to write them again. + // For Arrays with valid Smi length, we are sure to have no HeapNumber + // indices and thus we can skip this step. + for (uint32_t i = 0; i < nof_indices; i++) { + Object* index = combined_keys->get(i); + combined_keys->set(i, index); + } + } + } + + // Copy over the passed-in property keys. + CopyObjectToObjectElements(*keys, FAST_ELEMENTS, 0, *combined_keys, + FAST_ELEMENTS, nof_indices, nof_property_keys); + + if (IsHoleyElementsKind(kind())) { + // Shrink combined_keys to the final size. + int final_size = nof_indices + nof_property_keys; + DCHECK_LE(final_size, combined_keys->length()); + combined_keys->Shrink(final_size); + } + + return combined_keys; + } void AddElementsToKeyAccumulator(Handle<JSObject> receiver, KeyAccumulator* accumulator, @@ -919,12 +1066,7 @@ class ElementsAccessorBase : public ElementsAccessor { ? index : kMaxUInt32; } else { - uint32_t length = - holder->IsJSArray() - ? static_cast<uint32_t>( - Smi::cast(JSArray::cast(holder)->length())->value()) - : ElementsAccessorSubclass::GetCapacityImpl(holder, - backing_store); + uint32_t length = GetIterationLength(holder, backing_store); return index < length ? index : kMaxUInt32; } } @@ -961,6 +1103,19 @@ class DictionaryElementsAccessor : ElementsAccessorBase<DictionaryElementsAccessor, ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {} + static uint32_t GetIterationLength(JSObject* receiver, + FixedArrayBase* elements) { + uint32_t length; + if (receiver->IsJSArray()) { + // Special-case GetIterationLength for dictionary elements since the + // length of the array might be a HeapNumber. + JSArray::cast(receiver)->length()->ToArrayLength(&length); + } else { + length = GetCapacityImpl(receiver, elements); + } + return length; + } + static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array, uint32_t length, Handle<FixedArrayBase> backing_store) { @@ -1037,12 +1192,16 @@ class DictionaryElementsAccessor static bool HasAccessorsImpl(JSObject* holder, FixedArrayBase* backing_store) { + DisallowHeapAllocation no_gc; SeededNumberDictionary* dict = SeededNumberDictionary::cast(backing_store); if (!dict->requires_slow_elements()) return false; int capacity = dict->Capacity(); + Heap* heap = holder->GetHeap(); + Object* undefined = heap->undefined_value(); + Object* the_hole = heap->the_hole_value(); for (int i = 0; i < capacity; i++) { Object* key = dict->KeyAt(i); - if (!dict->IsKey(key)) continue; + if (key == the_hole || key == undefined) continue; DCHECK(!dict->IsDeleted(i)); PropertyDetails details = dict->DetailsAt(i); if (details.type() == ACCESSOR_CONSTANT) return true; @@ -1141,47 +1300,97 @@ class DictionaryElementsAccessor return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry); } + static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary, + int entry, Object* raw_key, PropertyFilter filter) { + DCHECK(!dictionary->IsDeleted(entry)); + DCHECK(raw_key->IsNumber()); + DCHECK_LE(raw_key->Number(), kMaxUInt32); + PropertyDetails details = dictionary->DetailsAt(entry); + PropertyAttributes attr = details.attributes(); + if ((attr & filter) != 0) return kMaxUInt32; + return static_cast<uint32_t>(raw_key->Number()); + } + + static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary, + int entry, PropertyFilter filter) { + DisallowHeapAllocation no_gc; + Object* raw_key = dictionary->KeyAt(entry); + if (!dictionary->IsKey(raw_key)) return kMaxUInt32; + return FilterKey(dictionary, entry, raw_key, filter); + } + + static uint32_t GetKeyForEntryImpl(Handle<SeededNumberDictionary> dictionary, + int entry, PropertyFilter filter, + Object* undefined, Object* the_hole) { + DisallowHeapAllocation no_gc; + Object* raw_key = dictionary->KeyAt(entry); + // Replace the IsKey check with a direct comparison which is much faster. + if (raw_key == undefined || raw_key == the_hole) { + return kMaxUInt32; + } + return FilterKey(dictionary, entry, raw_key, filter); + } + static void CollectElementIndicesImpl(Handle<JSObject> object, Handle<FixedArrayBase> backing_store, KeyAccumulator* keys, uint32_t range, PropertyFilter filter, uint32_t offset) { + if (filter & SKIP_STRINGS) return; + Isolate* isolate = keys->isolate(); + Handle<Object> undefined = isolate->factory()->undefined_value(); + Handle<Object> the_hole = isolate->factory()->the_hole_value(); Handle<SeededNumberDictionary> dictionary = Handle<SeededNumberDictionary>::cast(backing_store); int capacity = dictionary->Capacity(); for (int i = 0; i < capacity; i++) { - Object* k = dictionary->KeyAt(i); - if (!dictionary->IsKey(k)) continue; - if (k->FilterKey(filter)) continue; - if (dictionary->IsDeleted(i)) continue; - DCHECK(k->IsNumber()); - DCHECK_LE(k->Number(), kMaxUInt32); - uint32_t index = static_cast<uint32_t>(k->Number()); - if (index < offset) continue; - PropertyDetails details = dictionary->DetailsAt(i); - if (filter & ONLY_ALL_CAN_READ) { - if (details.kind() != kAccessor) continue; - Object* accessors = dictionary->ValueAt(i); - if (!accessors->IsAccessorInfo()) continue; - if (!AccessorInfo::cast(accessors)->all_can_read()) continue; - } - PropertyAttributes attr = details.attributes(); - if ((attr & filter) != 0) continue; - keys->AddKey(index); + uint32_t key = + GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole); + if (key == kMaxUInt32) continue; + keys->AddKey(key); } keys->SortCurrentElementsList(); } + static Handle<FixedArray> DirectCollectElementIndicesImpl( + Isolate* isolate, Handle<JSObject> object, + Handle<FixedArrayBase> backing_store, GetKeysConversion convert, + PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices, + uint32_t insertion_index = 0) { + if (filter & SKIP_STRINGS) return list; + if (filter & ONLY_ALL_CAN_READ) return list; + + Handle<Object> undefined = isolate->factory()->undefined_value(); + Handle<Object> the_hole = isolate->factory()->the_hole_value(); + Handle<SeededNumberDictionary> dictionary = + Handle<SeededNumberDictionary>::cast(backing_store); + uint32_t capacity = dictionary->Capacity(); + for (uint32_t i = 0; i < capacity; i++) { + uint32_t key = + GetKeyForEntryImpl(dictionary, i, filter, *undefined, *the_hole); + if (key == kMaxUInt32) continue; + Handle<Object> index = isolate->factory()->NewNumberFromUint(key); + list->set(insertion_index, *index); + insertion_index++; + } + *nof_indices = insertion_index; + return list; + } + static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, KeyAccumulator* accumulator, AddKeyConversion convert) { + Isolate* isolate = accumulator->isolate(); + Handle<Object> undefined = isolate->factory()->undefined_value(); + Handle<Object> the_hole = isolate->factory()->the_hole_value(); SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(receiver->elements()); int capacity = dictionary->Capacity(); for (int i = 0; i < capacity; i++) { Object* k = dictionary->KeyAt(i); - if (!dictionary->IsKey(k)) continue; + if (k == *undefined) continue; + if (k == *the_hole) continue; if (dictionary->IsDeleted(i)) continue; Object* value = dictionary->ValueAt(i); DCHECK(!value->IsTheHole()); @@ -1205,6 +1414,36 @@ class FastElementsAccessor typedef typename KindTraits::BackingStore BackingStore; + static Handle<SeededNumberDictionary> NormalizeImpl( + Handle<JSObject> object, Handle<FixedArrayBase> store) { + Isolate* isolate = store->GetIsolate(); + ElementsKind kind = FastElementsAccessorSubclass::kind(); + + // Ensure that notifications fire if the array or object prototypes are + // normalizing. + if (IsFastSmiOrObjectElementsKind(kind)) { + isolate->UpdateArrayProtectorOnNormalizeElements(object); + } + + int capacity = object->GetFastElementsUsage(); + Handle<SeededNumberDictionary> dictionary = + SeededNumberDictionary::New(isolate, capacity); + + PropertyDetails details = PropertyDetails::Empty(); + bool used_as_prototype = object->map()->is_prototype_map(); + int j = 0; + for (int i = 0; j < capacity; i++) { + if (IsHoleyElementsKind(kind)) { + if (BackingStore::cast(*store)->is_the_hole(i)) continue; + } + Handle<Object> value = FastElementsAccessorSubclass::GetImpl(*store, i); + dictionary = SeededNumberDictionary::AddNumberEntry( + dictionary, i, value, details, used_as_prototype); + j++; + } + return dictionary; + } + static void DeleteAtEnd(Handle<JSObject> obj, Handle<BackingStore> backing_store, uint32_t entry) { uint32_t length = static_cast<uint32_t>(backing_store->length()); @@ -1337,15 +1576,10 @@ class FastElementsAccessor static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, KeyAccumulator* accumulator, AddKeyConversion convert) { - uint32_t length = 0; Handle<FixedArrayBase> elements(receiver->elements(), receiver->GetIsolate()); - if (receiver->IsJSArray()) { - length = Smi::cast(JSArray::cast(*receiver)->length())->value(); - } else { - length = - FastElementsAccessorSubclass::GetCapacityImpl(*receiver, *elements); - } + uint32_t length = + FastElementsAccessorSubclass::GetIterationLength(*receiver, *elements); for (uint32_t i = 0; i < length; i++) { if (IsFastPackedElementsKind(KindTraits::Kind) || HasEntryImpl(*elements, i)) { @@ -1380,45 +1614,33 @@ class FastElementsAccessor #endif } - static Handle<Object> PopImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store) { - return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store, - AT_END); + static Handle<Object> PopImpl(Handle<JSArray> receiver) { + return FastElementsAccessorSubclass::RemoveElement(receiver, AT_END); } - static Handle<Object> ShiftImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store) { - return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store, - AT_START); + static Handle<Object> ShiftImpl(Handle<JSArray> receiver) { + return FastElementsAccessorSubclass::RemoveElement(receiver, AT_START); } static uint32_t PushImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, Arguments* args, uint32_t push_size) { + Handle<FixedArrayBase> backing_store(receiver->elements()); return FastElementsAccessorSubclass::AddArguments(receiver, backing_store, args, push_size, AT_END); } static uint32_t UnshiftImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, Arguments* args, uint32_t unshift_size) { + Handle<FixedArrayBase> backing_store(receiver->elements()); return FastElementsAccessorSubclass::AddArguments( receiver, backing_store, args, unshift_size, AT_START); } - static void MoveElements(Isolate* isolate, Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, int dst_index, - int src_index, int len, int hole_start, - int hole_end) { - UNREACHABLE(); - } - static Handle<JSArray> SliceImpl(Handle<JSObject> receiver, - Handle<FixedArrayBase> backing_store, uint32_t start, uint32_t end) { - DCHECK(start < end); Isolate* isolate = receiver->GetIsolate(); - int result_len = end - start; + Handle<FixedArrayBase> backing_store(receiver->elements(), isolate); + int result_len = end < start ? 0u : end - start; Handle<JSArray> result_array = isolate->factory()->NewJSArray( KindTraits::Kind, result_len, result_len); DisallowHeapAllocation no_gc; @@ -1431,7 +1653,6 @@ class FastElementsAccessor } static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, uint32_t start, uint32_t delete_count, Arguments* args, uint32_t add_count) { Isolate* isolate = receiver->GetIsolate(); @@ -1439,6 +1660,15 @@ class FastElementsAccessor uint32_t length = Smi::cast(receiver->length())->value(); uint32_t new_length = length - delete_count + add_count; + ElementsKind kind = KindTraits::Kind; + if (new_length <= static_cast<uint32_t>(receiver->elements()->length()) && + IsFastSmiOrObjectElementsKind(kind)) { + HandleScope scope(isolate); + JSObject::EnsureWritableFastElements(receiver); + } + + Handle<FixedArrayBase> backing_store(receiver->elements(), isolate); + if (new_length == 0) { receiver->set_elements(heap->empty_fixed_array()); receiver->set_length(Smi::FromInt(0)); @@ -1477,6 +1707,55 @@ class FastElementsAccessor return deleted_elements; } + static Maybe<bool> CollectValuesOrEntriesImpl( + Isolate* isolate, Handle<JSObject> object, + Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, + PropertyFilter filter) { + int count = 0; + uint32_t length = object->elements()->length(); + for (uint32_t index = 0; index < length; ++index) { + if (!HasEntryImpl(object->elements(), index)) continue; + Handle<Object> value = + FastElementsAccessorSubclass::GetImpl(object->elements(), index); + if (get_entries) { + value = MakeEntryPair(isolate, index, value); + } + values_or_entries->set(count++, *value); + } + *nof_items = count; + return Just(true); + } + + static void MoveElements(Isolate* isolate, Handle<JSArray> receiver, + Handle<FixedArrayBase> backing_store, int dst_index, + int src_index, int len, int hole_start, + int hole_end) { + Heap* heap = isolate->heap(); + Handle<BackingStore> dst_elms = Handle<BackingStore>::cast(backing_store); + if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) { + // Update all the copies of this backing_store handle. + *dst_elms.location() = + BackingStore::cast(heap->LeftTrimFixedArray(*dst_elms, src_index)); + receiver->set_elements(*dst_elms); + // Adjust the hole offset as the array has been shrunk. + hole_end -= src_index; + DCHECK_LE(hole_start, backing_store->length()); + DCHECK_LE(hole_end, backing_store->length()); + } else if (len != 0) { + if (IsFastDoubleElementsKind(KindTraits::Kind)) { + MemMove(dst_elms->data_start() + dst_index, + dst_elms->data_start() + src_index, len * kDoubleSize); + } else { + DisallowHeapAllocation no_gc; + heap->MoveElements(FixedArray::cast(*dst_elms), dst_index, src_index, + len); + } + } + if (hole_start != hole_end) { + dst_elms->FillWithHoles(hole_start, hole_end); + } + } + private: // SpliceShrinkStep might modify the backing_store. static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver, @@ -1523,9 +1802,14 @@ class FastElementsAccessor } static Handle<Object> RemoveElement(Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, Where remove_position) { Isolate* isolate = receiver->GetIsolate(); + ElementsKind kind = KindTraits::Kind; + if (IsFastSmiOrObjectElementsKind(kind)) { + HandleScope scope(isolate); + JSObject::EnsureWritableFastElements(receiver); + } + Handle<FixedArrayBase> backing_store(receiver->elements(), isolate); uint32_t length = static_cast<uint32_t>(Smi::cast(receiver->length())->value()); DCHECK(length > 0); @@ -1540,8 +1824,8 @@ class FastElementsAccessor FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length, backing_store); - if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) { - return receiver->GetIsolate()->factory()->undefined_value(); + if (IsHoleyElementsKind(kind) && result->IsTheHole()) { + return isolate->factory()->undefined_value(); } return result; } @@ -1551,7 +1835,7 @@ class FastElementsAccessor Arguments* args, uint32_t add_size, Where remove_position) { uint32_t length = Smi::cast(receiver->length())->value(); - DCHECK(add_size > 0); + DCHECK(0 < add_size); uint32_t elms_len = backing_store->length(); // Check we do not overflow the new_length. DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length)); @@ -1630,29 +1914,6 @@ class FastSmiOrObjectElementsAccessor return backing_store->get(index); } - static void MoveElements(Isolate* isolate, Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, int dst_index, - int src_index, int len, int hole_start, - int hole_end) { - Heap* heap = isolate->heap(); - Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store); - if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) { - // Update all the copies of this backing_store handle. - *dst_elms.location() = - FixedArray::cast(heap->LeftTrimFixedArray(*dst_elms, src_index)); - receiver->set_elements(*dst_elms); - // Adjust the hole offset as the array has been shrunk. - hole_end -= src_index; - DCHECK_LE(hole_start, backing_store->length()); - DCHECK_LE(hole_end, backing_store->length()); - } else if (len != 0) { - DisallowHeapAllocation no_gc; - heap->MoveElements(*dst_elms, dst_index, src_index, len); - } - if (hole_start != hole_end) { - dst_elms->FillWithHoles(hole_start, hole_end); - } - } // NOTE: this method violates the handlified function signature convention: // raw pointer parameters in the function that allocates. @@ -1784,31 +2045,6 @@ class FastDoubleElementsAccessor FixedDoubleArray::cast(backing_store)->set(entry, value->Number()); } - static void MoveElements(Isolate* isolate, Handle<JSArray> receiver, - Handle<FixedArrayBase> backing_store, int dst_index, - int src_index, int len, int hole_start, - int hole_end) { - Heap* heap = isolate->heap(); - Handle<FixedDoubleArray> dst_elms = - Handle<FixedDoubleArray>::cast(backing_store); - if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) { - // Update all the copies of this backing_store handle. - *dst_elms.location() = FixedDoubleArray::cast( - heap->LeftTrimFixedArray(*dst_elms, src_index)); - receiver->set_elements(*dst_elms); - // Adjust the hole offset as the array has been shrunk. - hole_end -= src_index; - DCHECK_LE(hole_start, backing_store->length()); - DCHECK_LE(hole_end, backing_store->length()); - } else if (len != 0) { - MemMove(dst_elms->data_start() + dst_index, - dst_elms->data_start() + src_index, len * kDoubleSize); - } - if (hole_start != hole_end) { - dst_elms->FillWithHoles(hole_start, hole_end); - } - } - static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start, FixedArrayBase* to, ElementsKind from_kind, uint32_t to_start, int packed_size, @@ -1965,14 +2201,33 @@ class TypedElementsAccessor static void AddElementsToKeyAccumulatorImpl(Handle<JSObject> receiver, KeyAccumulator* accumulator, AddKeyConversion convert) { - Handle<FixedArrayBase> elements(receiver->elements(), - receiver->GetIsolate()); + Handle<FixedArrayBase> elements(receiver->elements()); uint32_t length = AccessorClass::GetCapacityImpl(*receiver, *elements); for (uint32_t i = 0; i < length; i++) { Handle<Object> value = AccessorClass::GetImpl(*elements, i); accumulator->AddKey(value, convert); } } + + static Maybe<bool> CollectValuesOrEntriesImpl( + Isolate* isolate, Handle<JSObject> object, + Handle<FixedArray> values_or_entries, bool get_entries, int* nof_items, + PropertyFilter filter) { + int count = 0; + if ((filter & ONLY_CONFIGURABLE) == 0) { + Handle<FixedArrayBase> elements(object->elements()); + uint32_t length = AccessorClass::GetCapacityImpl(*object, *elements); + for (uint32_t index = 0; index < length; ++index) { + Handle<Object> value = AccessorClass::GetImpl(*elements, index); + if (get_entries) { + value = MakeEntryPair(isolate, index, value); + } + values_or_entries->set(count++, *value); + } + } + *nof_items = count; + return Just(true); + } }; @@ -2163,6 +2418,55 @@ class SloppyArgumentsElementsAccessor obj, entry - length); } } + + static void CollectElementIndicesImpl(Handle<JSObject> object, + Handle<FixedArrayBase> backing_store, + KeyAccumulator* keys, uint32_t range, + PropertyFilter filter, + uint32_t offset) { + FixedArray* parameter_map = FixedArray::cast(*backing_store); + uint32_t length = parameter_map->length() - 2; + if (range < length) length = range; + + for (uint32_t i = offset; i < length; ++i) { + if (!parameter_map->get(i + 2)->IsTheHole()) { + keys->AddKey(i); + } + } + + Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1))); + ArgumentsAccessor::CollectElementIndicesImpl(object, store, keys, range, + filter, offset); + if (SloppyArgumentsElementsAccessorSubclass::kind() == + FAST_SLOPPY_ARGUMENTS_ELEMENTS) { + keys->SortCurrentElementsList(); + } + } + + static Handle<FixedArray> DirectCollectElementIndicesImpl( + Isolate* isolate, Handle<JSObject> object, + Handle<FixedArrayBase> backing_store, GetKeysConversion convert, + PropertyFilter filter, Handle<FixedArray> list, uint32_t* nof_indices, + uint32_t insertion_index = 0) { + FixedArray* parameter_map = FixedArray::cast(*backing_store); + uint32_t length = parameter_map->length() - 2; + + for (uint32_t i = 0; i < length; ++i) { + if (parameter_map->get(i + 2)->IsTheHole()) continue; + if (convert == CONVERT_TO_STRING) { + Handle<String> index_string = isolate->factory()->Uint32ToString(i); + list->set(insertion_index, *index_string); + } else { + list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER); + } + insertion_index++; + } + + Handle<FixedArrayBase> store(FixedArrayBase::cast(parameter_map->get(1))); + return ArgumentsAccessor::DirectCollectElementIndicesImpl( + isolate, object, store, convert, filter, list, nof_indices, + insertion_index); + } }; @@ -2264,6 +2568,13 @@ class FastSloppyArgumentsElementsAccessor FastHoleyObjectElementsAccessor, ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {} + static Handle<SeededNumberDictionary> NormalizeImpl( + Handle<JSObject> object, Handle<FixedArrayBase> elements) { + FixedArray* parameter_map = FixedArray::cast(*elements); + Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); + return FastHoleyObjectElementsAccessor::NormalizeImpl(object, arguments); + } + static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) { FixedArray* parameter_map = FixedArray::cast(obj->elements()); Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1))); @@ -2452,11 +2763,9 @@ class StringWrapperElementsAccessor KeyAccumulator* keys, uint32_t range, PropertyFilter filter, uint32_t offset) { - if ((filter & ONLY_ALL_CAN_READ) == 0) { - uint32_t length = GetString(*object)->length(); - for (uint32_t i = 0; i < length; i++) { - keys->AddKey(i); - } + uint32_t length = GetString(*object)->length(); + for (uint32_t i = 0; i < length; i++) { + keys->AddKey(i); } BackingStoreAccessor::CollectElementIndicesImpl(object, backing_store, keys, range, filter, offset); @@ -2488,6 +2797,11 @@ class FastStringWrapperElementsAccessor : StringWrapperElementsAccessor< FastStringWrapperElementsAccessor, FastHoleyObjectElementsAccessor, ElementsKindTraits<FAST_STRING_WRAPPER_ELEMENTS>>(name) {} + + static Handle<SeededNumberDictionary> NormalizeImpl( + Handle<JSObject> object, Handle<FixedArrayBase> elements) { + return FastHoleyObjectElementsAccessor::NormalizeImpl(object, elements); + } }; class SlowStringWrapperElementsAccessor @@ -2664,62 +2978,66 @@ void ElementsAccessor::TearDown() { Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args, uint32_t concat_size) { - int result_len = 0; - ElementsKind elements_kind = GetInitialFastElementsKind(); - bool has_double = false; + const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); + STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); + USE(kHalfOfMaxInt); + uint32_t result_len = 0; + bool has_raw_doubles = false; + ElementsKind result_elements_kind = GetInitialFastElementsKind(); { DisallowHeapAllocation no_gc; + bool is_holey = false; // Iterate through all the arguments performing checks // and calculating total length. - bool is_holey = false; for (uint32_t i = 0; i < concat_size; i++) { - Object* arg = (*args)[i]; - int len = Smi::cast(JSArray::cast(arg)->length())->value(); + JSArray* array = JSArray::cast((*args)[i]); + uint32_t len = 0; + array->length()->ToArrayLength(&len); // We shouldn't overflow when adding another len. - const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); - STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); - USE(kHalfOfMaxInt); result_len += len; DCHECK(0 <= result_len); DCHECK(result_len <= FixedDoubleArray::kMaxLength); - ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind(); - has_double = has_double || IsFastDoubleElementsKind(arg_kind); + ElementsKind arg_kind = array->GetElementsKind(); + has_raw_doubles = has_raw_doubles || IsFastDoubleElementsKind(arg_kind); is_holey = is_holey || IsFastHoleyElementsKind(arg_kind); - elements_kind = GetMoreGeneralElementsKind(elements_kind, arg_kind); + result_elements_kind = + GetMoreGeneralElementsKind(result_elements_kind, arg_kind); } if (is_holey) { - elements_kind = GetHoleyElementsKind(elements_kind); + result_elements_kind = GetHoleyElementsKind(result_elements_kind); } } // If a double array is concatted into a fast elements array, the fast // elements array needs to be initialized to contain proper holes, since // boxing doubles may cause incremental marking. - ArrayStorageAllocationMode mode = - has_double && IsFastObjectElementsKind(elements_kind) - ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE - : DONT_INITIALIZE_ARRAY_ELEMENTS; + bool requires_double_boxing = + has_raw_doubles && !IsFastDoubleElementsKind(result_elements_kind); + ArrayStorageAllocationMode mode = requires_double_boxing + ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE + : DONT_INITIALIZE_ARRAY_ELEMENTS; Handle<JSArray> result_array = isolate->factory()->NewJSArray( - elements_kind, result_len, result_len, Strength::WEAK, mode); + result_elements_kind, result_len, result_len, mode); if (result_len == 0) return result_array; - int j = 0; + + uint32_t insertion_index = 0; Handle<FixedArrayBase> storage(result_array->elements(), isolate); - ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind); + ElementsAccessor* accessor = ElementsAccessor::ForKind(result_elements_kind); for (uint32_t i = 0; i < concat_size; i++) { // It is crucial to keep |array| in a raw pointer form to avoid // performance degradation. JSArray* array = JSArray::cast((*args)[i]); - int len = Smi::cast(array->length())->value(); - if (len > 0) { - ElementsKind from_kind = array->GetElementsKind(); - accessor->CopyElements(array, 0, from_kind, storage, j, len); - j += len; - } + uint32_t len = 0; + array->length()->ToArrayLength(&len); + if (len == 0) continue; + ElementsKind from_kind = array->GetElementsKind(); + accessor->CopyElements(array, 0, from_kind, storage, insertion_index, len); + insertion_index += len; } - DCHECK(j == result_len); + DCHECK_EQ(insertion_index, result_len); return result_array; } |