Revision: 14705
Author:   [email protected]
Date:     Thu May 16 04:19:37 2013
Log: Implement Array.observe and emit splice change records for ArrayPush

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

Patch from Rafael Weinstein <[email protected]>.
http://code.google.com/p/v8/source/detail?r=14705

Modified:
 /branches/bleeding_edge/src/array.js
 /branches/bleeding_edge/src/object-observe.js
 /branches/bleeding_edge/test/mjsunit/harmony/object-observe.js

=======================================
--- /branches/bleeding_edge/src/array.js        Thu Apr 11 05:15:25 2013
+++ /branches/bleeding_edge/src/array.js        Thu May 16 04:19:37 2013
@@ -416,6 +416,26 @@
 }


+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() {
@@ -423,6 +443,9 @@
     throw MakeTypeError("called_on_null_or_undefined",
                         ["Array.prototype.push"]);
   }
+
+  if (%IsObserved(this))
+    return ObservedArrayPush.apply(this, arguments);

   var n = TO_UINT32(this.length);
   var m = %_ArgumentsLength();
=======================================
--- /branches/bleeding_edge/src/object-observe.js       Wed May 15 15:09:40 2013
+++ /branches/bleeding_edge/src/object-observe.js       Thu May 16 04:19:37 2013
@@ -166,7 +166,7 @@
                        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 @@
   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 @@
   if (IS_UNDEFINED(objectInfo))
     return object;

-  ensureObserverRemoved(objectInfo, callback);
+  EnsureObserverRemoved(objectInfo, callback);

   if (objectInfo.changeObservers.length === 0 &&
       objectInfo.inactiveObservers.length === 0) {
@@ -249,6 +249,17 @@

   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.
@@ -270,6 +281,39 @@
     }
   }
 }
+
+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);
@@ -405,6 +449,10 @@
     "observe", ObjectObserve,
     "unobserve", ObjectUnobserve
   ));
+  InstallFunctions($Array, DONT_ENUM, $Array(
+    "observe", ArrayObserve,
+    "unobserve", ArrayUnobserve
+  ));
   InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
     "notify", ObjectNotifierNotify,
     "performChange", ObjectNotifierPerformChange
=======================================
--- /branches/bleeding_edge/test/mjsunit/harmony/object-observe.js Wed May 15 15:09:40 2013 +++ /branches/bleeding_edge/test/mjsunit/harmony/object-observe.js Thu May 16 04:19:37 2013
@@ -1068,13 +1068,22 @@
 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

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.


Reply via email to