summaryrefslogtreecommitdiff
path: root/deps/v8/src/elements.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/elements.cc')
-rw-r--r--deps/v8/src/elements.cc724
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;
}