Commit 8ce07187 authored by rossberg@chromium.org's avatar rossberg@chromium.org

Implement Array.observe and emit splice change records for ArrayPush

Review URL: https://codereview.chromium.org/14978007

Patch from Rafael Weinstein <rafaelw@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14705 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent c3dde4bd
......@@ -416,6 +416,26 @@ function ArrayPop() {
}
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() {
......@@ -424,6 +444,9 @@ 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++) {
......
......@@ -166,7 +166,7 @@ function EndPerformChange(objectInfo, type) {
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) {
......@@ -219,7 +219,7 @@ function ObjectObserve(object, callback, accept) {
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))
......@@ -240,7 +240,7 @@ function ObjectUnobserve(object, callback) {
if (IS_UNDEFINED(objectInfo))
return object;
ensureObserverRemoved(objectInfo, callback);
EnsureObserverRemoved(objectInfo, callback);
if (objectInfo.changeObservers.length === 0 &&
objectInfo.inactiveObservers.length === 0) {
......@@ -250,6 +250,17 @@ function ObjectUnobserve(object, callback) {
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;
......@@ -271,6 +282,39 @@ function EnqueueChangeRecord(changeRecord, observers) {
}
}
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)
......@@ -405,6 +449,10 @@ function SetupObjectObserve() {
"observe", ObjectObserve,
"unobserve", ObjectUnobserve
));
InstallFunctions($Array, DONT_ENUM, $Array(
"observe", ArrayObserve,
"unobserve", ArrayUnobserve
));
InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
"notify", ObjectNotifierNotify,
"performChange", ObjectNotifierPerformChange
......
......@@ -1068,13 +1068,22 @@ observer.assertCallbackRecords([
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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment