From b72e5811e7a1d789b3c0e9c9038b7f41cb359503 Mon Sep 17 00:00:00 2001 From: "rossberg@chromium.org" Date: Fri, 9 Nov 2012 10:57:54 +0000 Subject: [PATCH] Object.observe: notify when element addition causes array growth Review URL: https://codereview.chromium.org/11369135 Patch from Adam Klein . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12914 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/objects.cc | 14 ++++++++++++-- test/mjsunit/harmony/object-observe.js | 22 ++++++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/objects.cc b/src/objects.cc index 65c0058..551b8ed 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -10308,6 +10308,7 @@ MaybeObject* JSObject::SetElement(uint32_t index, // From here on, everything has to be handlified. Handle name; Handle old_value(isolate->heap()->the_hole_value()); + Handle 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::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::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 newValue = Object::GetElement(self, index); - if (!newValue->SameValue(*old_value)) + Handle new_value = Object::GetElement(self, index); + if (!new_value->SameValue(*old_value)) EnqueueChangeRecord(self, "updated", name, old_value); } } diff --git a/test/mjsunit/harmony/object-observe.js b/test/mjsunit/harmony/object-observe.js index 231fe91..2576e45 100644 --- a/test/mjsunit/harmony/object-observe.js +++ b/test/mjsunit/harmony/object-observe.js @@ -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' }, +]); -- 2.7.4