[Object.observe] Implement implicit notification from performChange
authorrafaelw@chromium.org <rafaelw@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 11:23:08 +0000 (11:23 +0000)
committerrafaelw@chromium.org <rafaelw@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Tue, 5 Nov 2013 11:23:08 +0000 (11:23 +0000)
R=arv@chromium.org, rossberg@chromium.org, rossberg
BUG=v8:2942

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17476 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/object-observe.js
test/mjsunit/harmony/object-observe.js

index 9c7ac38..9fd611a 100644 (file)
@@ -386,8 +386,28 @@ function ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
   %SetObserverDeliveryPending();
 }
 
-function ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord,
-                                       skipAccessCheck) {
+function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) {
+  if (!ObjectInfoHasActiveObservers(objectInfo))
+    return;
+
+  var hasType = !IS_UNDEFINED(type);
+  var newRecord = hasType ?
+      { object: ObjectInfoGetObject(objectInfo), type: type } :
+      { object: ObjectInfoGetObject(objectInfo) };
+
+  for (var prop in changeRecord) {
+    if (prop === 'object' || (hasType && prop === 'type')) continue;
+    %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop],
+        READ_ONLY + DONT_DELETE);
+  }
+  ObjectFreeze(newRecord);
+
+  ObjectInfoEnqueueInternalChangeRecord(objectInfo, newRecord,
+                                        true /* skip access check */);
+}
+
+function ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord,
+                                               skipAccessCheck) {
   // TODO(rossberg): adjust once there is a story for symbols vs proxies.
   if (IS_SYMBOL(changeRecord.name)) return;
 
@@ -435,7 +455,7 @@ function EnqueueSpliceRecord(array, index, removed, addedCount) {
 
   ObjectFreeze(changeRecord);
   ObjectFreeze(changeRecord.removed);
-  ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord);
+  ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
 }
 
 function NotifyChange(type, object, name, oldValue) {
@@ -447,7 +467,7 @@ function NotifyChange(type, object, name, oldValue) {
       { type: type, object: object, name: name } :
       { type: type, object: object, name: name, oldValue: oldValue };
   ObjectFreeze(changeRecord);
-  ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord);
+  ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
 }
 
 var notifierPrototype = {};
@@ -462,19 +482,7 @@ function ObjectNotifierNotify(changeRecord) {
   if (!IS_STRING(changeRecord.type))
     throw MakeTypeError("observe_type_non_string");
 
-  if (!ObjectInfoHasActiveObservers(objectInfo))
-    return;
-
-  var newRecord = { object: ObjectInfoGetObject(objectInfo) };
-  for (var prop in changeRecord) {
-    if (prop === 'object') continue;
-    %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop],
-        READ_ONLY + DONT_DELETE);
-  }
-  ObjectFreeze(newRecord);
-
-  ObjectInfoEnqueueChangeRecord(objectInfo, newRecord,
-                                true /* skip access check */);
+  ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord);
 }
 
 function ObjectNotifierPerformChange(changeType, changeFn) {
@@ -491,11 +499,16 @@ function ObjectNotifierPerformChange(changeType, changeFn) {
     throw MakeTypeError("observe_perform_non_function");
 
   ObjectInfoAddPerformingType(objectInfo, changeType);
+
+  var changeRecord;
   try {
-    %_CallFunction(UNDEFINED, changeFn);
+    changeRecord = %_CallFunction(UNDEFINED, changeFn);
   } finally {
     ObjectInfoRemovePerformingType(objectInfo, changeType);
   }
+
+  if (IS_SPEC_OBJECT(changeRecord))
+    ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType);
 }
 
 function ObjectGetNotifier(object) {
index f94ab75..5615d9e 100644 (file)
@@ -434,12 +434,10 @@ Thingy.prototype = {
     notifier.performChange(Thingy.INCREMENT, function() {
       self.a += amount;
       self.b += amount;
-    });
 
-    notifier.notify({
-      object: this,
-      type: Thingy.INCREMENT,
-      incremented: amount
+      return {
+        incremented: amount
+      };  // implicit notify
     });
   },
 
@@ -450,12 +448,10 @@ Thingy.prototype = {
     notifier.performChange(Thingy.MULTIPLY, function() {
       self.a *= amount;
       self.b *= amount;
-    });
 
-    notifier.notify({
-      object: this,
-      type: Thingy.MULTIPLY,
-      multiplied: amount
+      return {
+        multiplied: amount
+      };  // implicit notify
     });
   },
 
@@ -466,13 +462,11 @@ Thingy.prototype = {
     notifier.performChange(Thingy.INCREMENT_AND_MULTIPLY, function() {
       self.increment(incAmount);
       self.multiply(multAmount);
-    });
 
-    notifier.notify({
-      object: this,
-      type: Thingy.INCREMENT_AND_MULTIPLY,
-      incremented: incAmount,
-      multiplied: multAmount
+      return {
+        incremented: incAmount,
+        multiplied: multAmount
+      };  // implicit notify
     });
   }
 }
@@ -545,7 +539,6 @@ RecursiveThingy.prototype = {
     });
 
     notifier.notify({
-      object: this,
       type: RecursiveThingy.MULTIPLY_FIRST_N,
       multiplied: amount,
       n: n
@@ -606,7 +599,6 @@ DeckSuit.prototype = {
     });
 
     notifier.notify({
-      object: this,
       type: DeckSuit.SHUFFLE
     });
   },