| Index: src/objects.cc
|
| diff --git a/src/objects.cc b/src/objects.cc
|
| index 0825b64c3367e5d2d92bcd5a8374b3ec616eef6e..ac0c60da11946ec2b9e460b26b6ac52fdb0c96f7 100644
|
| --- a/src/objects.cc
|
| +++ b/src/objects.cc
|
| @@ -9351,6 +9351,25 @@ void JSArray::Expand(int required_size) {
|
| }
|
|
|
|
|
| +// Returns false if the passed-in index is marked non-configurable,
|
| +// which will cause the ES5 truncation operation to halt, and thus
|
| +// no further old values need be collected.
|
| +static bool GetOldValue(Isolate* isolate,
|
| + Handle<JSObject> object,
|
| + uint32_t index,
|
| + List<Handle<Object> >* old_values,
|
| + List<Handle<String> >* indices) {
|
| + PropertyAttributes attributes = object->GetLocalElementAttribute(index);
|
| + ASSERT(attributes != ABSENT);
|
| + if (attributes == DONT_DELETE) return false;
|
| + old_values->Add(object->GetLocalElementAccessorPair(index) == NULL
|
| + ? Object::GetElement(object, index)
|
| + : Handle<Object>::cast(isolate->factory()->the_hole_value()));
|
| + indices->Add(isolate->factory()->Uint32ToString(index));
|
| + return true;
|
| +}
|
| +
|
| +
|
| MaybeObject* JSArray::SetElementsLength(Object* len) {
|
| // We should never end in here with a pixel or external array.
|
| ASSERT(AllowsSetElementsLength());
|
| @@ -9370,19 +9389,28 @@ MaybeObject* JSArray::SetElementsLength(Object* len) {
|
| if (!new_length_handle->ToArrayIndex(&new_length))
|
| return Failure::InternalError();
|
|
|
| - // TODO(adamk): This loop can be very slow for arrays in dictionary mode.
|
| - // Find another way to iterate over arrays with dictionary elements.
|
| - for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
|
| - PropertyAttributes attributes = self->GetLocalElementAttribute(i);
|
| - if (attributes == ABSENT) continue;
|
| - // A non-configurable property will cause the truncation operation to
|
| - // stop at this index.
|
| - if (attributes == DONT_DELETE) break;
|
| - old_values.Add(
|
| - self->GetLocalElementAccessorPair(i) == NULL
|
| - ? Object::GetElement(self, i)
|
| - : Handle<Object>::cast(isolate->factory()->the_hole_value()));
|
| - indices.Add(isolate->factory()->Uint32ToString(i));
|
| + // Observed arrays should always be in dictionary mode;
|
| + // if they were in fast mode, the below is slower than necessary
|
| + // as it iterates over the array backing store multiple times.
|
| + ASSERT(self->HasDictionaryElements());
|
| + static const PropertyAttributes kNoAttrFilter = NONE;
|
| + int num_elements = self->NumberOfLocalElements(kNoAttrFilter);
|
| + if (num_elements > 0) {
|
| + if (old_length == static_cast<uint32_t>(num_elements)) {
|
| + // Simple case for arrays without holes.
|
| + for (uint32_t i = old_length - 1; i + 1 > new_length; --i) {
|
| + if (!GetOldValue(isolate, self, i, &old_values, &indices)) break;
|
| + }
|
| + } else {
|
| + // For sparse arrays, only iterate over existing elements.
|
| + Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements);
|
| + self->GetLocalElementKeys(*keys, kNoAttrFilter);
|
| + while (num_elements-- > 0) {
|
| + uint32_t index = NumberToUint32(keys->get(num_elements));
|
| + if (index < new_length) break;
|
| + if (!GetOldValue(isolate, self, index, &old_values, &indices)) break;
|
| + }
|
| + }
|
| }
|
|
|
| MaybeObject* result =
|
|
|