summaryrefslogtreecommitdiff
path: root/deps/v8/src/object-observe.js
diff options
context:
space:
mode:
authorFedor Indutny <fedor.indutny@gmail.com>2014-03-13 20:45:44 +0400
committerFedor Indutny <fedor.indutny@gmail.com>2014-03-13 20:56:54 +0400
commit1c7bf245dc2d520c005e01bcb56ecb3275971395 (patch)
tree34d8160c98bd8dd33757252d87a0f6586fea8213 /deps/v8/src/object-observe.js
parent93c3674ff7115fb2a3dbb5b4ffd22f4d5ed9a472 (diff)
downloadnode-new-1c7bf245dc2d520c005e01bcb56ecb3275971395.tar.gz
deps: update v8 to 3.24.40
Diffstat (limited to 'deps/v8/src/object-observe.js')
-rw-r--r--deps/v8/src/object-observe.js147
1 files changed, 93 insertions, 54 deletions
diff --git a/deps/v8/src/object-observe.js b/deps/v8/src/object-observe.js
index 9c7ac3889e..468da31ec2 100644
--- a/deps/v8/src/object-observe.js
+++ b/deps/v8/src/object-observe.js
@@ -91,10 +91,14 @@ var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
var notifierObjectInfoMap =
new ObservationWeakMap(observationState.notifierObjectInfoMap);
-function TypeMapCreate() {
+function nullProtoObject() {
return { __proto__: null };
}
+function TypeMapCreate() {
+ return nullProtoObject();
+}
+
function TypeMapAddType(typeMap, type, ignoreDuplicate) {
typeMap[type] = ignoreDuplicate ? 1 : (typeMap[type] || 0) + 1;
}
@@ -128,11 +132,12 @@ function TypeMapIsDisjointFrom(typeMap1, typeMap2) {
}
var defaultAcceptTypes = TypeMapCreateFromList([
- 'new',
- 'updated',
- 'deleted',
- 'prototype',
- 'reconfigured'
+ 'add',
+ 'update',
+ 'delete',
+ 'setPrototype',
+ 'reconfigure',
+ 'preventExtensions'
]);
// An Observer is a registration to observe an object by a callback with
@@ -141,11 +146,12 @@ var defaultAcceptTypes = TypeMapCreateFromList([
// to the callback. An observer never changes its accept types and thus never
// needs to "normalize".
function ObserverCreate(callback, acceptList) {
- return IS_UNDEFINED(acceptList) ? callback : {
- __proto__: null,
- callback: callback,
- accept: TypeMapCreateFromList(acceptList)
- };
+ if (IS_UNDEFINED(acceptList))
+ return callback;
+ var observer = nullProtoObject();
+ observer.callback = callback;
+ observer.accept = TypeMapCreateFromList(acceptList);
+ return observer;
}
function ObserverGetCallback(observer) {
@@ -161,8 +167,8 @@ function ObserverIsActive(observer, objectInfo) {
ObserverGetAcceptTypes(observer));
}
-function ObjectInfoGet(object) {
- var objectInfo = objectInfoMap.get(object);
+function ObjectInfoGetOrCreate(object) {
+ var objectInfo = ObjectInfoGet(object);
if (IS_UNDEFINED(objectInfo)) {
if (!%IsJSProxy(object))
%SetIsObserved(object);
@@ -179,6 +185,10 @@ function ObjectInfoGet(object) {
return objectInfo;
}
+function ObjectInfoGet(object) {
+ return objectInfoMap.get(object);
+}
+
function ObjectInfoGetFromNotifier(notifier) {
return notifierObjectInfoMap.get(notifier);
}
@@ -211,7 +221,7 @@ function ObjectInfoNormalizeChangeObservers(objectInfo) {
var callback = ObserverGetCallback(observer);
var callbackInfo = CallbackInfoGet(callback);
var priority = CallbackInfoGetPriority(callbackInfo);
- objectInfo.changeObservers = { __proto__: null };
+ objectInfo.changeObservers = nullProtoObject();
objectInfo.changeObservers[priority] = observer;
}
}
@@ -242,7 +252,7 @@ function ObjectInfoRemoveObserver(objectInfo, callback) {
var callbackInfo = CallbackInfoGet(callback);
var priority = CallbackInfoGetPriority(callbackInfo);
- delete objectInfo.changeObservers[priority];
+ objectInfo.changeObservers[priority] = null;
}
function ObjectInfoHasActiveObservers(objectInfo) {
@@ -253,7 +263,8 @@ function ObjectInfoHasActiveObservers(objectInfo) {
return ObserverIsActive(objectInfo.changeObservers, objectInfo);
for (var priority in objectInfo.changeObservers) {
- if (ObserverIsActive(objectInfo.changeObservers[priority], objectInfo))
+ var observer = objectInfo.changeObservers[priority];
+ if (!IS_NULL(observer) && ObserverIsActive(observer, objectInfo))
return true;
}
@@ -332,7 +343,7 @@ function ObjectObserve(object, callback, acceptList) {
if (!AcceptArgIsValid(acceptList))
throw MakeTypeError("observe_accept_invalid");
- var objectInfo = ObjectInfoGet(object);
+ var objectInfo = ObjectInfoGetOrCreate(object);
ObjectInfoAddObserver(objectInfo, callback, acceptList);
return object;
}
@@ -343,7 +354,7 @@ function ObjectUnobserve(object, callback) {
if (!IS_SPEC_FUNCTION(callback))
throw MakeTypeError("observe_non_function", ["unobserve"]);
- var objectInfo = objectInfoMap.get(object);
+ var objectInfo = ObjectInfoGet(object);
if (IS_UNDEFINED(objectInfo))
return object;
@@ -352,9 +363,9 @@ function ObjectUnobserve(object, callback) {
}
function ArrayObserve(object, callback) {
- return ObjectObserve(object, callback, ['new',
- 'updated',
- 'deleted',
+ return ObjectObserve(object, callback, ['add',
+ 'update',
+ 'delete',
'splice']);
}
@@ -379,15 +390,37 @@ function ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
}
var callbackInfo = CallbackInfoNormalize(callback);
- if (!observationState.pendingObservers)
- observationState.pendingObservers = { __proto__: null };
+ if (IS_NULL(observationState.pendingObservers)) {
+ observationState.pendingObservers = nullProtoObject();
+ GetMicrotaskQueue().push(ObserveMicrotaskRunner);
+ %SetMicrotaskPending(true);
+ }
observationState.pendingObservers[callbackInfo.priority] = callback;
callbackInfo.push(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;
@@ -403,25 +436,27 @@ function ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord,
for (var priority in objectInfo.changeObservers) {
var observer = objectInfo.changeObservers[priority];
+ if (IS_NULL(observer))
+ continue;
ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
needsAccessCheck);
}
}
function BeginPerformSplice(array) {
- var objectInfo = objectInfoMap.get(array);
+ var objectInfo = ObjectInfoGet(array);
if (!IS_UNDEFINED(objectInfo))
ObjectInfoAddPerformingType(objectInfo, 'splice');
}
function EndPerformSplice(array) {
- var objectInfo = objectInfoMap.get(array);
+ var objectInfo = ObjectInfoGet(array);
if (!IS_UNDEFINED(objectInfo))
ObjectInfoRemovePerformingType(objectInfo, 'splice');
}
function EnqueueSpliceRecord(array, index, removed, addedCount) {
- var objectInfo = objectInfoMap.get(array);
+ var objectInfo = ObjectInfoGet(array);
if (!ObjectInfoHasActiveObservers(objectInfo))
return;
@@ -435,19 +470,30 @@ function EnqueueSpliceRecord(array, index, removed, addedCount) {
ObjectFreeze(changeRecord);
ObjectFreeze(changeRecord.removed);
- ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord);
+ ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
}
function NotifyChange(type, object, name, oldValue) {
- var objectInfo = objectInfoMap.get(object);
+ var objectInfo = ObjectInfoGet(object);
if (!ObjectInfoHasActiveObservers(objectInfo))
return;
- var changeRecord = (arguments.length < 4) ?
- { type: type, object: object, name: name } :
- { type: type, object: object, name: name, oldValue: oldValue };
+ var changeRecord;
+ if (arguments.length == 2) {
+ changeRecord = { type: type, object: object };
+ } else if (arguments.length == 3) {
+ changeRecord = { type: type, object: object, name: name };
+ } else {
+ changeRecord = {
+ type: type,
+ object: object,
+ name: name,
+ oldValue: oldValue
+ };
+ }
+
ObjectFreeze(changeRecord);
- ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord);
+ ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
}
var notifierPrototype = {};
@@ -462,19 +508,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 +525,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) {
@@ -504,7 +543,7 @@ function ObjectGetNotifier(object) {
if (ObjectIsFrozen(object)) return null;
- var objectInfo = ObjectInfoGet(object);
+ var objectInfo = ObjectInfoGetOrCreate(object);
return ObjectInfoGetNotifier(objectInfo);
}
@@ -526,7 +565,7 @@ function CallbackDeliverPending(callback) {
try {
%_CallFunction(UNDEFINED, delivered, callback);
- } catch (ex) {}
+ } catch (ex) {} // TODO(rossberg): perhaps log uncaught exceptions.
return true;
}
@@ -537,9 +576,9 @@ function ObjectDeliverChangeRecords(callback) {
while (CallbackDeliverPending(callback)) {}
}
-function DeliverChangeRecords() {
- while (observationState.pendingObservers) {
- var pendingObservers = observationState.pendingObservers;
+function ObserveMicrotaskRunner() {
+ var pendingObservers = observationState.pendingObservers;
+ if (pendingObservers) {
observationState.pendingObservers = null;
for (var i in pendingObservers) {
CallbackDeliverPending(pendingObservers[i]);