Index: src/elements.cc |
diff --git a/src/elements.cc b/src/elements.cc |
index 7109342902bd6d6bbbd64dc1cb98ba1988023769..d7727710635f2337aab91ce6406d0e0e2ba33768 100644 |
--- a/src/elements.cc |
+++ b/src/elements.cc |
@@ -428,7 +428,6 @@ static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base, |
} |
} |
- |
static void TraceTopFrame(Isolate* isolate) { |
StackFrameIterator it(isolate); |
if (it.done()) { |
@@ -730,6 +729,16 @@ class ElementsAccessorBase : public ElementsAccessor { |
JSObject::ValidateElements(array); |
} |
+ static uint32_t GetIterationLength(JSObject* receiver, |
+ FixedArrayBase* elements) { |
+ if (receiver->IsJSArray()) { |
+ return static_cast<uint32_t>( |
+ Smi::cast(JSArray::cast(receiver)->length())->value()); |
+ } else { |
+ return ElementsAccessorSubclass::GetCapacityImpl(receiver, elements); |
+ } |
+ } |
+ |
static Handle<FixedArrayBase> ConvertElementsWithCapacity( |
Handle<JSObject> object, Handle<FixedArrayBase> old_elements, |
ElementsKind from_kind, uint32_t capacity) { |
@@ -846,6 +855,14 @@ class ElementsAccessorBase : public ElementsAccessor { |
from, from_start, *to, from_kind, to_start, packed_size, copy_size); |
} |
+ 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 void CollectElementIndicesImpl(Handle<JSObject> object, |
Handle<FixedArrayBase> backing_store, |
KeyAccumulator* keys, uint32_t range, |
@@ -856,30 +873,104 @@ class ElementsAccessorBase : public ElementsAccessor { |
// 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); |
- } |
+ 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 length = |
+ ElementsAccessorSubclass::GetIterationLength(*object, *backing_store); |
+ uint32_t insertion_index = 0; |
+ 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())) { |
+ 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); |
+ // 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); |
+ } |
+ } |
+ } |
+ |
+ // 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, |
@@ -912,12 +1003,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; |
} |
} |
@@ -1119,6 +1205,28 @@ class DictionaryElementsAccessor |
return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry); |
} |
+ 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; |
+ if (raw_key->FilterKey(filter)) return kMaxUInt32; |
+ if (dictionary->IsDeleted(entry)) return kMaxUInt32; |
+ DCHECK(raw_key->IsNumber()); |
+ DCHECK_LE(raw_key->Number(), kMaxUInt32); |
+ uint32_t key = static_cast<uint32_t>(raw_key->Number()); |
+ PropertyDetails details = dictionary->DetailsAt(entry); |
+ if (filter & ONLY_ALL_CAN_READ) { |
+ if (details.kind() != kAccessor) return kMaxUInt32; |
+ Object* accessors = dictionary->ValueAt(entry); |
+ if (!accessors->IsAccessorInfo()) return kMaxUInt32; |
+ if (!AccessorInfo::cast(accessors)->all_can_read()) return kMaxUInt32; |
+ } |
+ PropertyAttributes attr = details.attributes(); |
+ if ((attr & filter) != 0) return kMaxUInt32; |
+ return key; |
+ } |
+ |
static void CollectElementIndicesImpl(Handle<JSObject> object, |
Handle<FixedArrayBase> backing_store, |
KeyAccumulator* keys, uint32_t range, |
@@ -1128,29 +1236,33 @@ class DictionaryElementsAccessor |
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); |
+ 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) { |
+ Handle<SeededNumberDictionary> dictionary = |
+ Handle<SeededNumberDictionary>::cast(backing_store); |
+ uint32_t capacity = dictionary->Capacity(); |
+ uint32_t insertion_index = 0; |
+ for (uint32_t i = 0; i < capacity; i++) { |
+ uint32_t key = GetKeyForEntryImpl(dictionary, i, filter); |
+ 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) { |
@@ -1315,15 +1427,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)) { |