Index: src/accessors.cc |
diff --git a/src/accessors.cc b/src/accessors.cc |
index 1bc9221a20c5c973c020bfea7f90cd0a46ce4316..8ed31c4450d96ef5aabd69d5bfa29893f3d0b834 100644 |
--- a/src/accessors.cc |
+++ b/src/accessors.cc |
@@ -95,6 +95,47 @@ Object* Accessors::FlattenNumber(Object* value) { |
} |
+static MaybeObject* ArraySetLengthObserved(Isolate* isolate, |
+ Handle<JSArray> array, |
+ Handle<Object> new_length_handle) { |
+ List<Handle<String> > indices; |
+ List<Handle<Object> > old_values; |
+ Handle<Object> old_length_handle(array->length(), isolate); |
+ uint32_t old_length; |
+ CHECK(old_length_handle->ToArrayIndex(&old_length)); |
+ uint32_t new_length; |
+ CHECK(new_length_handle->ToArrayIndex(&new_length)); |
+ // 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 = array->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; |
+ // TODO(adamk): Don't fetch the old value if it's an accessor. |
+ old_values.Add(Object::GetElement(array, i)); |
+ indices.Add(isolate->factory()->Uint32ToString(i)); |
+ } |
+ |
+ MaybeObject* result = array->SetElementsLength(*new_length_handle); |
+ Handle<Object> hresult; |
+ if (!result->ToHandle(&hresult)) return result; |
+ |
+ CHECK(array->length()->ToArrayIndex(&new_length)); |
+ if (old_length != new_length) { |
+ for (int i = 0; i < indices.length(); ++i) { |
+ JSObject::EnqueueChangeRecord( |
+ array, "deleted", indices[i], old_values[i]); |
+ } |
+ JSObject::EnqueueChangeRecord( |
+ array, "updated", isolate->factory()->length_symbol(), |
+ old_length_handle); |
+ } |
+ return *hresult; |
+} |
+ |
+ |
MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { |
Isolate* isolate = object->GetIsolate(); |
@@ -112,7 +153,7 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { |
HandleScope scope(isolate); |
// Protect raw pointers. |
- Handle<JSObject> object_handle(object, isolate); |
+ Handle<JSArray> array_handle(JSArray::cast(object), isolate); |
Handle<Object> value_handle(value, isolate); |
bool has_exception; |
@@ -122,7 +163,11 @@ MaybeObject* Accessors::ArraySetLength(JSObject* object, Object* value, void*) { |
if (has_exception) return Failure::Exception(); |
if (uint32_v->Number() == number_v->Number()) { |
- return Handle<JSArray>::cast(object_handle)->SetElementsLength(*uint32_v); |
+ if (FLAG_harmony_observation && array_handle->map()->is_observed()) { |
+ return ArraySetLengthObserved(isolate, array_handle, uint32_v); |
+ } else { |
+ return array_handle->SetElementsLength(*uint32_v); |
+ } |
} |
return isolate->Throw( |
*isolate->factory()->NewRangeError("invalid_array_length", |