Object.observe: notify when element addition causes array growth

Review URL: https://codereview.chromium.org/11369135
Patch from Adam Klein <adamk@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12914 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
rossberg@chromium.org 2012-11-09 10:57:54 +00:00
parent 127b944ab5
commit b72e5811e7
2 changed files with 34 additions and 2 deletions

View File

@ -10308,6 +10308,7 @@ MaybeObject* JSObject::SetElement(uint32_t index,
// From here on, everything has to be handlified.
Handle<String> name;
Handle<Object> old_value(isolate->heap()->the_hole_value());
Handle<Object> old_array_length;
PropertyAttributes old_attributes = ABSENT;
bool preexists = false;
if (FLAG_harmony_observation && map()->is_observed()) {
@ -10317,6 +10318,9 @@ MaybeObject* JSObject::SetElement(uint32_t index,
old_attributes = self->GetLocalPropertyAttribute(*name);
// TODO(observe): only read & set old_value if we have a data property
old_value = Object::GetElement(self, index);
} else if (self->IsJSArray()) {
// Store old array length in case adding an element grows the array.
old_array_length = handle(Handle<JSArray>::cast(self)->length());
}
}
@ -10334,11 +10338,17 @@ MaybeObject* JSObject::SetElement(uint32_t index,
PropertyAttributes new_attributes = self->GetLocalPropertyAttribute(*name);
if (!preexists) {
EnqueueChangeRecord(self, "new", name, old_value);
if (self->IsJSArray() &&
!old_array_length->SameValue(Handle<JSArray>::cast(self)->length())) {
EnqueueChangeRecord(self, "updated",
isolate->factory()->length_symbol(),
old_array_length);
}
} else if (new_attributes != old_attributes || old_value->IsTheHole()) {
EnqueueChangeRecord(self, "reconfigured", name, old_value);
} else {
Handle<Object> newValue = Object::GetElement(self, index);
if (!newValue->SameValue(*old_value))
Handle<Object> new_value = Object::GetElement(self, index);
if (!new_value->SameValue(*old_value))
EnqueueChangeRecord(self, "updated", name, old_value);
}
}

View File

@ -399,3 +399,25 @@ observer.assertCallbackRecords([
{ object: obj, name: "3", type: "new" },
{ object: obj, name: "4", type: "new" },
]);
// Adding elements past the end of an array should notify on length
reset();
var arr = [1, 2, 3];
Object.observe(arr, observer.callback);
arr[3] = 10;
arr[100] = 20;
Object.defineProperty(arr, '200', {value: 7});
Object.defineProperty(arr, '400', {get: function(){}});
arr[50] = 30; // no length change expected
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
{ object: arr, name: '3', type: 'new' },
{ object: arr, name: 'length', type: 'updated', oldValue: 3 },
{ object: arr, name: '100', type: 'new' },
{ object: arr, name: 'length', type: 'updated', oldValue: 4 },
{ object: arr, name: '200', type: 'new' },
{ object: arr, name: 'length', type: 'updated', oldValue: 101 },
{ object: arr, name: '400', type: 'new' },
{ object: arr, name: 'length', type: 'updated', oldValue: 201 },
{ object: arr, name: '50', type: 'new' },
]);