}
+function ObservedArrayPush() {
+ var n = TO_UINT32(this.length);
+ var m = %_ArgumentsLength();
+
+ EnqueueSpliceRecord(this, n, [], 0, m);
+
+ try {
+ BeginPerformSplice(this);
+
+ for (var i = 0; i < m; i++) {
+ this[i+n] = %_Arguments(i);
+ }
+ this.length = n + m;
+ } finally {
+ EndPerformSplice(this);
+ }
+
+ return this.length;
+}
+
// Appends the arguments to the end of the array and returns the new
// length of the array. See ECMA-262, section 15.4.4.7.
function ArrayPush() {
["Array.prototype.push"]);
}
+ if (%IsObserved(this))
+ return ObservedArrayPush.apply(this, arguments);
+
var n = TO_UINT32(this.length);
var m = %_ArgumentsLength();
for (var i = 0; i < m; i++) {
objectInfo);
}
-function ensureObserverRemoved(objectInfo, callback) {
+function EnsureObserverRemoved(objectInfo, callback) {
function remove(observerList) {
for (var i = 0; i < observerList.length; i++) {
if (observerList[i].callback === callback) {
if (IS_UNDEFINED(objectInfo)) objectInfo = CreateObjectInfo(object);
%SetIsObserved(object, true);
- ensureObserverRemoved(objectInfo, callback);
+ EnsureObserverRemoved(objectInfo, callback);
var observer = CreateObserver(callback, accept);
if (ObserverIsActive(observer, objectInfo))
if (IS_UNDEFINED(objectInfo))
return object;
- ensureObserverRemoved(objectInfo, callback);
+ EnsureObserverRemoved(objectInfo, callback);
if (objectInfo.changeObservers.length === 0 &&
objectInfo.inactiveObservers.length === 0) {
return object;
}
+function ArrayObserve(object, callback) {
+ return ObjectObserve(object, callback, ['new',
+ 'updated',
+ 'deleted',
+ 'splice']);
+}
+
+function ArrayUnobserve(object, callback) {
+ return ObjectUnobserve(object, callback);
+}
+
function EnqueueChangeRecord(changeRecord, observers) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(changeRecord.name)) return;
}
}
+function BeginPerformSplice(array) {
+ var objectInfo = objectInfoMap.get(array);
+ if (!IS_UNDEFINED(objectInfo))
+ BeginPerformChange(objectInfo, 'splice');
+}
+
+function EndPerformSplice(array) {
+ var objectInfo = objectInfoMap.get(array);
+ if (!IS_UNDEFINED(objectInfo))
+ EndPerformChange(objectInfo, 'splice');
+}
+
+function EnqueueSpliceRecord(array, index, removed, deleteCount, addedCount) {
+ var objectInfo = objectInfoMap.get(array);
+ if (IS_UNDEFINED(objectInfo) || objectInfo.changeObservers.length === 0)
+ return;
+
+ var changeRecord = {
+ type: 'splice',
+ object: array,
+ index: index,
+ removed: removed,
+ addedCount: addedCount
+ };
+
+ changeRecord.removed.length = deleteCount;
+ // TODO(rafaelw): This breaks spec-compliance. Re-enable when freezing isn't
+ // slow.
+ // ObjectFreeze(changeRecord);
+ // ObjectFreeze(changeRecord.removed);
+ EnqueueChangeRecord(changeRecord, objectInfo.changeObservers);
+}
+
function NotifyChange(type, object, name, oldValue) {
var objectInfo = objectInfoMap.get(object);
if (objectInfo.changeObservers.length === 0)
"observe", ObjectObserve,
"unobserve", ObjectUnobserve
));
+ InstallFunctions($Array, DONT_ENUM, $Array(
+ "observe", ArrayObserve,
+ "unobserve", ArrayUnobserve
+ ));
InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
"notify", ObjectNotifierNotify,
"performChange", ObjectNotifierPerformChange
reset();
var array = [1, 2];
Object.observe(array, observer.callback);
+Array.observe(array, observer2.callback);
array.push(3, 4);
+array.push(5);
Object.deliverChangeRecords(observer.callback);
observer.assertCallbackRecords([
{ object: array, name: '2', type: 'new' },
{ object: array, name: 'length', type: 'updated', oldValue: 2 },
{ object: array, name: '3', type: 'new' },
{ object: array, name: 'length', type: 'updated', oldValue: 3 },
+ { object: array, name: '4', type: 'new' },
+ { object: array, name: 'length', type: 'updated', oldValue: 4 },
+]);
+Object.deliverChangeRecords(observer2.callback);
+observer2.assertCallbackRecords([
+ { object: array, type: 'splice', index: 2, removed: [], addedCount: 2 },
+ { object: array, type: 'splice', index: 4, removed: [], addedCount: 1 }
]);
// Pop