Commit a6a8455f authored by adamk@chromium.org's avatar adamk@chromium.org

Revert "This patch implements optimized objectInfo structure which manages the...

Revert "This patch implements optimized objectInfo structure which manages the set of observers associated with an object and the changeRecord types which they accept."

This reverts r16539 as it triggers crashes on the GC stress bot.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16540 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b26d28d9
...@@ -27,41 +27,12 @@ ...@@ -27,41 +27,12 @@
"use strict"; "use strict";
// Overview:
//
// This file contains all of the routing and accounting for Object.observe.
// User code will interact with these mechanisms via the Object.observe APIs
// and, as a side effect of mutation objects which are observed. The V8 runtime
// (both C++ and JS) will interact with these mechanisms primarily by enqueuing
// proper change records for objects which were mutated. The Object.observe
// routing and accounting consists primarily of three participants
//
// 1) ObjectInfo. This represents the observed state of a given object. It
// records what callbacks are observing the object, with what options, and
// what "change types" are in progress on the object (i.e. via
// notifier.performChange).
//
// 2) CallbackInfo. This represents a callback used for observation. It holds
// the records which must be delivered to the callback, as well as the global
// priority of the callback (which determines delivery order between
// callbacks).
//
// 3) observationState.pendingObservers. This is the set of observers which
// have change records which must be delivered. During "normal" delivery
// (i.e. not Object.deliverChangeRecords), this is the mechanism by which
// callbacks are invoked in the proper order until there are no more
// change records pending to a callback.
//
// Note that in order to reduce allocation and processing costs, the
// implementation of (1) and (2) have "optimized" states which represent
// common cases which can be handled more efficiently.
var observationState = %GetObservationState(); var observationState = %GetObservationState();
if (IS_UNDEFINED(observationState.callbackInfoMap)) { if (IS_UNDEFINED(observationState.callbackInfoMap)) {
observationState.callbackInfoMap = %ObservationWeakMapCreate(); observationState.callbackInfoMap = %ObservationWeakMapCreate();
observationState.objectInfoMap = %ObservationWeakMapCreate(); observationState.objectInfoMap = %ObservationWeakMapCreate();
observationState.notifierObjectInfoMap = %ObservationWeakMapCreate(); observationState.notifierTargetMap = %ObservationWeakMapCreate();
observationState.pendingObservers = null; observationState.pendingObservers = new InternalArray;
observationState.nextCallbackPriority = 0; observationState.nextCallbackPriority = 0;
} }
...@@ -88,191 +59,126 @@ ObservationWeakMap.prototype = { ...@@ -88,191 +59,126 @@ ObservationWeakMap.prototype = {
var callbackInfoMap = var callbackInfoMap =
new ObservationWeakMap(observationState.callbackInfoMap); new ObservationWeakMap(observationState.callbackInfoMap);
var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap); var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
var notifierObjectInfoMap = var notifierTargetMap =
new ObservationWeakMap(observationState.notifierObjectInfoMap); new ObservationWeakMap(observationState.notifierTargetMap);
function TypeMapCreate() { function CreateObjectInfo(object) {
return { __proto__: null }; var info = {
} changeObservers: new InternalArray,
notifier: null,
function TypeMapAddType(typeMap, type, ignoreDuplicate) { inactiveObservers: new InternalArray,
typeMap[type] = ignoreDuplicate ? 1 : (typeMap[type] || 0) + 1; performing: { __proto__: null },
} performingCount: 0,
};
function TypeMapRemoveType(typeMap, type) { objectInfoMap.set(object, info);
typeMap[type]--; return info;
}
function TypeMapCreateFromList(typeList) {
var typeMap = TypeMapCreate();
for (var i = 0; i < typeList.length; i++) {
TypeMapAddType(typeMap, typeList[i], true);
}
return typeMap;
}
function TypeMapHasType(typeMap, type) {
return !!typeMap[type];
} }
function TypeMapIsDisjointFrom(typeMap1, typeMap2) { var defaultAcceptTypes = {
if (!typeMap1 || !typeMap2) __proto__: null,
return true; 'new': true,
'updated': true,
for (var type in typeMap1) { 'deleted': true,
if (TypeMapHasType(typeMap1, type) && TypeMapHasType(typeMap2, type)) 'prototype': true,
return false; 'reconfigured': true
} };
return true;
}
var defaultAcceptTypes = TypeMapCreateFromList([ function CreateObserver(callback, accept) {
'new', var observer = {
'updated',
'deleted',
'prototype',
'reconfigured'
]);
// An Observer is a registration to observe an object by a callback with
// a given set of accept types. If the set of accept types is the default
// set for Object.observe, the observer is represented as a direct reference
// 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, __proto__: null,
callback: callback, callback: callback,
accept: TypeMapCreateFromList(acceptList) accept: defaultAcceptTypes
}; };
}
function ObserverGetCallback(observer) { if (IS_UNDEFINED(accept))
return IS_SPEC_FUNCTION(observer) ? observer : observer.callback; return observer;
}
function ObserverGetAcceptTypes(observer) { var acceptMap = { __proto__: null };
return IS_SPEC_FUNCTION(observer) ? defaultAcceptTypes : observer.accept; for (var i = 0; i < accept.length; i++)
} acceptMap[accept[i]] = true;
function ObserverIsActive(observer, objectInfo) { observer.accept = acceptMap;
return TypeMapIsDisjointFrom(ObjectInfoGetPerformingTypes(objectInfo), return observer;
ObserverGetAcceptTypes(observer));
} }
function ObjectInfoGet(object) { function ObserverIsActive(observer, objectInfo) {
var objectInfo = objectInfoMap.get(object); if (objectInfo.performingCount === 0)
if (IS_UNDEFINED(objectInfo)) { return true;
if (!%IsJSProxy(object))
%SetIsObserved(object);
objectInfo = {
object: object,
changeObservers: null,
notifier: null,
performing: null,
performingCount: 0,
};
objectInfoMap.set(object, objectInfo);
}
return objectInfo;
}
function ObjectInfoGetFromNotifier(notifier) {
return notifierObjectInfoMap.get(notifier);
}
function ObjectInfoGetNotifier(objectInfo) { var performing = objectInfo.performing;
if (IS_NULL(objectInfo.notifier)) { for (var type in performing) {
objectInfo.notifier = { __proto__: notifierPrototype }; if (performing[type] > 0 && observer.accept[type])
notifierObjectInfoMap.set(objectInfo.notifier, objectInfo); return false;
} }
return objectInfo.notifier; return true;
}
function ObjectInfoGetObject(objectInfo) {
return objectInfo.object;
}
function ChangeObserversIsOptimized(changeObservers) {
return typeof changeObservers === 'function' ||
typeof changeObservers.callback === 'function';
} }
// The set of observers on an object is called 'changeObservers'. The first function ObserverIsInactive(observer, objectInfo) {
// observer is referenced directly via objectInfo.changeObservers. When a second return !ObserverIsActive(observer, objectInfo);
// is added, changeObservers "normalizes" to become a mapping of callback
// priority -> observer and is then stored on objectInfo.changeObservers.
function ObjectInfoNormalizeChangeObservers(objectInfo) {
if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
var observer = objectInfo.changeObservers;
var callback = ObserverGetCallback(observer);
var callbackInfo = CallbackInfoGet(callback);
var priority = CallbackInfoGetPriority(callbackInfo);
objectInfo.changeObservers = { __proto__: null };
objectInfo.changeObservers[priority] = observer;
}
} }
function ObjectInfoAddObserver(objectInfo, callback, acceptList) { function RemoveNullElements(from) {
var callbackInfo = CallbackInfoGetOrCreate(callback); var i = 0;
var observer = ObserverCreate(callback, acceptList); var j = 0;
for (; i < from.length; i++) {
if (!objectInfo.changeObservers) { if (from[i] === null)
objectInfo.changeObservers = observer; continue;
return; if (j < i)
from[j] = from[i];
j++;
} }
ObjectInfoNormalizeChangeObservers(objectInfo); if (i !== j)
var priority = CallbackInfoGetPriority(callbackInfo); from.length = from.length - (i - j);
objectInfo.changeObservers[priority] = observer;
} }
function ObjectInfoRemoveObserver(objectInfo, callback) { function RepartitionObservers(conditionFn, from, to, objectInfo) {
if (!objectInfo.changeObservers) var anyRemoved = false;
return; for (var i = 0; i < from.length; i++) {
var observer = from[i];
if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { if (conditionFn(observer, objectInfo)) {
if (callback === ObserverGetCallback(objectInfo.changeObservers)) anyRemoved = true;
objectInfo.changeObservers = null; from[i] = null;
return; to.push(observer);
} }
var callbackInfo = CallbackInfoGet(callback);
var priority = CallbackInfoGetPriority(callbackInfo);
delete objectInfo.changeObservers[priority];
}
function ObjectInfoHasActiveObservers(objectInfo) {
if (IS_UNDEFINED(objectInfo) || !objectInfo.changeObservers)
return false;
if (ChangeObserversIsOptimized(objectInfo.changeObservers))
return ObserverIsActive(objectInfo.changeObservers, objectInfo);
for (var priority in objectInfo.changeObservers) {
if (ObserverIsActive(objectInfo.changeObservers[priority], objectInfo))
return true;
} }
return false; if (anyRemoved)
RemoveNullElements(from);
} }
function ObjectInfoAddPerformingType(objectInfo, type) { function BeginPerformChange(objectInfo, type) {
objectInfo.performing = objectInfo.performing || TypeMapCreate(); objectInfo.performing[type] = (objectInfo.performing[type] || 0) + 1;
TypeMapAddType(objectInfo.performing, type);
objectInfo.performingCount++; objectInfo.performingCount++;
RepartitionObservers(ObserverIsInactive,
objectInfo.changeObservers,
objectInfo.inactiveObservers,
objectInfo);
} }
function ObjectInfoRemovePerformingType(objectInfo, type) { function EndPerformChange(objectInfo, type) {
objectInfo.performing[type]--;
objectInfo.performingCount--; objectInfo.performingCount--;
TypeMapRemoveType(objectInfo.performing, type); RepartitionObservers(ObserverIsActive,
} objectInfo.inactiveObservers,
objectInfo.changeObservers,
objectInfo);
}
function EnsureObserverRemoved(objectInfo, callback) {
function remove(observerList) {
for (var i = 0; i < observerList.length; i++) {
if (observerList[i].callback === callback) {
observerList.splice(i, 1);
return true;
}
}
return false;
}
function ObjectInfoGetPerformingTypes(objectInfo) { if (!remove(objectInfo.changeObservers))
return objectInfo.performingCount > 0 ? objectInfo.performing : null; remove(objectInfo.inactiveObservers);
} }
function AcceptArgIsValid(arg) { function AcceptArgIsValid(arg) {
...@@ -292,31 +198,12 @@ function AcceptArgIsValid(arg) { ...@@ -292,31 +198,12 @@ function AcceptArgIsValid(arg) {
return true; return true;
} }
// CallbackInfo's optimized state is just a number which represents its global function EnsureCallbackPriority(callback) {
// priority. When a change record must be enqueued for the callback, it if (!callbackInfoMap.has(callback))
// normalizes. When delivery clears any pending change records, it re-optimizes. callbackInfoMap.set(callback, observationState.nextCallbackPriority++);
function CallbackInfoGet(callback) {
return callbackInfoMap.get(callback);
} }
function CallbackInfoGetOrCreate(callback) { function NormalizeCallbackInfo(callback) {
var callbackInfo = callbackInfoMap.get(callback);
if (!IS_UNDEFINED(callbackInfo))
return callbackInfo;
var priority = observationState.nextCallbackPriority++
callbackInfoMap.set(callback, priority);
return priority;
}
function CallbackInfoGetPriority(callbackInfo) {
if (IS_NUMBER(callbackInfo))
return callbackInfo;
else
return callbackInfo.priority;
}
function CallbackInfoNormalize(callback) {
var callbackInfo = callbackInfoMap.get(callback); var callbackInfo = callbackInfoMap.get(callback);
if (IS_NUMBER(callbackInfo)) { if (IS_NUMBER(callbackInfo)) {
var priority = callbackInfo; var priority = callbackInfo;
...@@ -327,18 +214,32 @@ function CallbackInfoNormalize(callback) { ...@@ -327,18 +214,32 @@ function CallbackInfoNormalize(callback) {
return callbackInfo; return callbackInfo;
} }
function ObjectObserve(object, callback, acceptList) { function ObjectObserve(object, callback, accept) {
if (!IS_SPEC_OBJECT(object)) if (!IS_SPEC_OBJECT(object))
throw MakeTypeError("observe_non_object", ["observe"]); throw MakeTypeError("observe_non_object", ["observe"]);
if (!IS_SPEC_FUNCTION(callback)) if (!IS_SPEC_FUNCTION(callback))
throw MakeTypeError("observe_non_function", ["observe"]); throw MakeTypeError("observe_non_function", ["observe"]);
if (ObjectIsFrozen(callback)) if (ObjectIsFrozen(callback))
throw MakeTypeError("observe_callback_frozen"); throw MakeTypeError("observe_callback_frozen");
if (!AcceptArgIsValid(acceptList)) if (!AcceptArgIsValid(accept))
throw MakeTypeError("observe_accept_invalid"); throw MakeTypeError("observe_accept_invalid");
var objectInfo = ObjectInfoGet(object); EnsureCallbackPriority(callback);
ObjectInfoAddObserver(objectInfo, callback, acceptList);
var objectInfo = objectInfoMap.get(object);
if (IS_UNDEFINED(objectInfo)) {
objectInfo = CreateObjectInfo(object);
%SetIsObserved(object);
}
EnsureObserverRemoved(objectInfo, callback);
var observer = CreateObserver(callback, accept);
if (ObserverIsActive(observer, objectInfo))
objectInfo.changeObservers.push(observer);
else
objectInfo.inactiveObservers.push(observer);
return object; return object;
} }
...@@ -352,7 +253,7 @@ function ObjectUnobserve(object, callback) { ...@@ -352,7 +253,7 @@ function ObjectUnobserve(object, callback) {
if (IS_UNDEFINED(objectInfo)) if (IS_UNDEFINED(objectInfo))
return object; return object;
ObjectInfoRemoveObserver(objectInfo, callback); EnsureObserverRemoved(objectInfo, callback);
return object; return object;
} }
...@@ -367,52 +268,41 @@ function ArrayUnobserve(object, callback) { ...@@ -367,52 +268,41 @@ function ArrayUnobserve(object, callback) {
return ObjectUnobserve(object, callback); return ObjectUnobserve(object, callback);
} }
function ObserverEnqueueIfActive(observer, objectInfo, changeRecord) { function EnqueueToCallback(callback, changeRecord) {
if (!ObserverIsActive(observer, objectInfo) || var callbackInfo = NormalizeCallbackInfo(callback);
!TypeMapHasType(ObserverGetAcceptTypes(observer), changeRecord.type)) {
return;
}
var callback = ObserverGetCallback(observer);
var callbackInfo = CallbackInfoNormalize(callback);
if (!observationState.pendingObservers)
observationState.pendingObservers = { __proto__: null };
observationState.pendingObservers[callbackInfo.priority] = callback; observationState.pendingObservers[callbackInfo.priority] = callback;
callbackInfo.push(changeRecord); callbackInfo.push(changeRecord);
%SetObserverDeliveryPending(); %SetObserverDeliveryPending();
} }
function ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord) { function EnqueueChangeRecord(changeRecord, observers) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies. // TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(changeRecord.name)) return; if (IS_SYMBOL(changeRecord.name)) return;
if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { for (var i = 0; i < observers.length; i++) {
var observer = objectInfo.changeObservers; var observer = observers[i];
ObserverEnqueueIfActive(observer, objectInfo, changeRecord); if (IS_UNDEFINED(observer.accept[changeRecord.type]))
return; continue;
}
for (var priority in objectInfo.changeObservers) { EnqueueToCallback(observer.callback, changeRecord);
var observer = objectInfo.changeObservers[priority];
ObserverEnqueueIfActive(observer, objectInfo, changeRecord);
} }
} }
function BeginPerformSplice(array) { function BeginPerformSplice(array) {
var objectInfo = objectInfoMap.get(array); var objectInfo = objectInfoMap.get(array);
if (!IS_UNDEFINED(objectInfo)) if (!IS_UNDEFINED(objectInfo))
ObjectInfoAddPerformingType(objectInfo, 'splice'); BeginPerformChange(objectInfo, 'splice');
} }
function EndPerformSplice(array) { function EndPerformSplice(array) {
var objectInfo = objectInfoMap.get(array); var objectInfo = objectInfoMap.get(array);
if (!IS_UNDEFINED(objectInfo)) if (!IS_UNDEFINED(objectInfo))
ObjectInfoRemovePerformingType(objectInfo, 'splice'); EndPerformChange(objectInfo, 'splice');
} }
function EnqueueSpliceRecord(array, index, removed, addedCount) { function EnqueueSpliceRecord(array, index, removed, addedCount) {
var objectInfo = objectInfoMap.get(array); var objectInfo = objectInfoMap.get(array);
if (!ObjectInfoHasActiveObservers(objectInfo)) if (IS_UNDEFINED(objectInfo) || objectInfo.changeObservers.length === 0)
return; return;
var changeRecord = { var changeRecord = {
...@@ -425,19 +315,19 @@ function EnqueueSpliceRecord(array, index, removed, addedCount) { ...@@ -425,19 +315,19 @@ function EnqueueSpliceRecord(array, index, removed, addedCount) {
ObjectFreeze(changeRecord); ObjectFreeze(changeRecord);
ObjectFreeze(changeRecord.removed); ObjectFreeze(changeRecord.removed);
ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord); EnqueueChangeRecord(changeRecord, objectInfo.changeObservers);
} }
function NotifyChange(type, object, name, oldValue) { function NotifyChange(type, object, name, oldValue) {
var objectInfo = objectInfoMap.get(object); var objectInfo = objectInfoMap.get(object);
if (!ObjectInfoHasActiveObservers(objectInfo)) if (objectInfo.changeObservers.length === 0)
return; return;
var changeRecord = (arguments.length < 4) ? var changeRecord = (arguments.length < 4) ?
{ type: type, object: object, name: name } : { type: type, object: object, name: name } :
{ type: type, object: object, name: name, oldValue: oldValue }; { type: type, object: object, name: name, oldValue: oldValue };
ObjectFreeze(changeRecord); ObjectFreeze(changeRecord);
ObjectInfoEnqueueChangeRecord(objectInfo, changeRecord); EnqueueChangeRecord(changeRecord, objectInfo.changeObservers);
} }
var notifierPrototype = {}; var notifierPrototype = {};
...@@ -446,16 +336,17 @@ function ObjectNotifierNotify(changeRecord) { ...@@ -446,16 +336,17 @@ function ObjectNotifierNotify(changeRecord) {
if (!IS_SPEC_OBJECT(this)) if (!IS_SPEC_OBJECT(this))
throw MakeTypeError("called_on_non_object", ["notify"]); throw MakeTypeError("called_on_non_object", ["notify"]);
var objectInfo = ObjectInfoGetFromNotifier(this); var target = notifierTargetMap.get(this);
if (IS_UNDEFINED(objectInfo)) if (IS_UNDEFINED(target))
throw MakeTypeError("observe_notify_non_notifier"); throw MakeTypeError("observe_notify_non_notifier");
if (!IS_STRING(changeRecord.type)) if (!IS_STRING(changeRecord.type))
throw MakeTypeError("observe_type_non_string"); throw MakeTypeError("observe_type_non_string");
if (!ObjectInfoHasActiveObservers(objectInfo)) var objectInfo = objectInfoMap.get(target);
if (IS_UNDEFINED(objectInfo) || objectInfo.changeObservers.length === 0)
return; return;
var newRecord = { object: ObjectInfoGetObject(objectInfo) }; var newRecord = { object: target };
for (var prop in changeRecord) { for (var prop in changeRecord) {
if (prop === 'object') continue; if (prop === 'object') continue;
%DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop], %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop],
...@@ -463,16 +354,15 @@ function ObjectNotifierNotify(changeRecord) { ...@@ -463,16 +354,15 @@ function ObjectNotifierNotify(changeRecord) {
} }
ObjectFreeze(newRecord); ObjectFreeze(newRecord);
ObjectInfoEnqueueChangeRecord(objectInfo, newRecord); EnqueueChangeRecord(newRecord, objectInfo.changeObservers);
} }
function ObjectNotifierPerformChange(changeType, changeFn, receiver) { function ObjectNotifierPerformChange(changeType, changeFn, receiver) {
if (!IS_SPEC_OBJECT(this)) if (!IS_SPEC_OBJECT(this))
throw MakeTypeError("called_on_non_object", ["performChange"]); throw MakeTypeError("called_on_non_object", ["performChange"]);
var objectInfo = ObjectInfoGetFromNotifier(this); var target = notifierTargetMap.get(this);
if (IS_UNDEFINED(target))
if (IS_UNDEFINED(objectInfo))
throw MakeTypeError("observe_notify_non_notifier"); throw MakeTypeError("observe_notify_non_notifier");
if (!IS_STRING(changeType)) if (!IS_STRING(changeType))
throw MakeTypeError("observe_perform_non_string"); throw MakeTypeError("observe_perform_non_string");
...@@ -485,11 +375,15 @@ function ObjectNotifierPerformChange(changeType, changeFn, receiver) { ...@@ -485,11 +375,15 @@ function ObjectNotifierPerformChange(changeType, changeFn, receiver) {
receiver = ToObject(receiver); receiver = ToObject(receiver);
} }
ObjectInfoAddPerformingType(objectInfo, changeType); var objectInfo = objectInfoMap.get(target);
if (IS_UNDEFINED(objectInfo))
return;
BeginPerformChange(objectInfo, changeType);
try { try {
%_CallFunction(receiver, changeFn); %_CallFunction(receiver, changeFn);
} finally { } finally {
ObjectInfoRemovePerformingType(objectInfo, changeType); EndPerformChange(objectInfo, changeType);
} }
} }
...@@ -499,8 +393,18 @@ function ObjectGetNotifier(object) { ...@@ -499,8 +393,18 @@ function ObjectGetNotifier(object) {
if (ObjectIsFrozen(object)) return null; if (ObjectIsFrozen(object)) return null;
var objectInfo = ObjectInfoGet(object); var objectInfo = objectInfoMap.get(object);
return ObjectInfoGetNotifier(objectInfo); if (IS_UNDEFINED(objectInfo)) {
objectInfo = CreateObjectInfo(object);
%SetIsObserved(object);
}
if (IS_NULL(objectInfo.notifier)) {
objectInfo.notifier = { __proto__: notifierPrototype };
notifierTargetMap.set(objectInfo.notifier, object);
}
return objectInfo.notifier;
} }
function CallbackDeliverPending(callback) { function CallbackDeliverPending(callback) {
...@@ -513,9 +417,7 @@ function CallbackDeliverPending(callback) { ...@@ -513,9 +417,7 @@ function CallbackDeliverPending(callback) {
var priority = callbackInfo.priority; var priority = callbackInfo.priority;
callbackInfoMap.set(callback, priority); callbackInfoMap.set(callback, priority);
if (observationState.pendingObservers) delete observationState.pendingObservers[priority];
delete observationState.pendingObservers[priority];
var delivered = []; var delivered = [];
%MoveArrayContents(callbackInfo, delivered); %MoveArrayContents(callbackInfo, delivered);
...@@ -533,9 +435,9 @@ function ObjectDeliverChangeRecords(callback) { ...@@ -533,9 +435,9 @@ function ObjectDeliverChangeRecords(callback) {
} }
function DeliverChangeRecords() { function DeliverChangeRecords() {
while (observationState.pendingObservers) { while (observationState.pendingObservers.length) {
var pendingObservers = observationState.pendingObservers; var pendingObservers = observationState.pendingObservers;
observationState.pendingObservers = null; observationState.pendingObservers = new InternalArray;
for (var i in pendingObservers) { for (var i in pendingObservers) {
CallbackDeliverPending(pendingObservers[i]); CallbackDeliverPending(pendingObservers[i]);
} }
......
...@@ -435,14 +435,14 @@ TEST(ObservationWeakMap) { ...@@ -435,14 +435,14 @@ TEST(ObservationWeakMap) {
i::Handle<i::JSWeakMap> objectInfoMap = i::Handle<i::JSWeakMap> objectInfoMap =
i::Handle<i::JSWeakMap>::cast( i::Handle<i::JSWeakMap>::cast(
i::GetProperty(observation_state, "objectInfoMap")); i::GetProperty(observation_state, "objectInfoMap"));
i::Handle<i::JSWeakMap> notifierObjectInfoMap = i::Handle<i::JSWeakMap> notifierTargetMap =
i::Handle<i::JSWeakMap>::cast( i::Handle<i::JSWeakMap>::cast(
i::GetProperty(observation_state, "notifierObjectInfoMap")); i::GetProperty(observation_state, "notifierTargetMap"));
CHECK_EQ(1, NumberOfElements(callbackInfoMap)); CHECK_EQ(1, NumberOfElements(callbackInfoMap));
CHECK_EQ(1, NumberOfElements(objectInfoMap)); CHECK_EQ(1, NumberOfElements(objectInfoMap));
CHECK_EQ(1, NumberOfElements(notifierObjectInfoMap)); CHECK_EQ(1, NumberOfElements(notifierTargetMap));
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(0, NumberOfElements(callbackInfoMap)); CHECK_EQ(0, NumberOfElements(callbackInfoMap));
CHECK_EQ(0, NumberOfElements(objectInfoMap)); CHECK_EQ(0, NumberOfElements(objectInfoMap));
CHECK_EQ(0, NumberOfElements(notifierObjectInfoMap)); CHECK_EQ(0, NumberOfElements(notifierTargetMap));
} }
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