"use strict";
var observationState = %GetObservationState();
-if (IS_UNDEFINED(observationState.observerInfoMap)) {
- observationState.observerInfoMap = %ObservationWeakMapCreate();
+if (IS_UNDEFINED(observationState.callbackInfoMap)) {
+ observationState.callbackInfoMap = %ObservationWeakMapCreate();
observationState.objectInfoMap = %ObservationWeakMapCreate();
observationState.notifierTargetMap = %ObservationWeakMapCreate();
observationState.pendingObservers = new InternalArray;
- observationState.observerPriority = 0;
+ observationState.nextCallbackPriority = 0;
}
function ObservationWeakMap(map) {
}
};
-var observerInfoMap =
- new ObservationWeakMap(observationState.observerInfoMap);
+var callbackInfoMap =
+ new ObservationWeakMap(observationState.callbackInfoMap);
var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
var notifierTargetMap =
new ObservationWeakMap(observationState.notifierTargetMap);
return true;
}
+function EnsureCallbackPriority(callback) {
+ if (!callbackInfoMap.has(callback))
+ callbackInfoMap.set(callback, observationState.nextCallbackPriority++);
+}
+
+function NormalizeCallbackInfo(callback) {
+ var callbackInfo = callbackInfoMap.get(callback);
+ if (IS_NUMBER(callbackInfo)) {
+ var priority = callbackInfo;
+ callbackInfo = new InternalArray;
+ callbackInfo.priority = priority;
+ callbackInfoMap.set(callback, callbackInfo);
+ }
+ return callbackInfo;
+}
+
function ObjectObserve(object, callback, accept) {
if (!IS_SPEC_OBJECT(object))
throw MakeTypeError("observe_non_object", ["observe"]);
if (!AcceptArgIsValid(accept))
throw MakeTypeError("observe_accept_invalid");
- if (!observerInfoMap.has(callback)) {
- observerInfoMap.set(callback, {
- pendingChangeRecords: null,
- priority: observationState.observerPriority++,
- });
- }
+ EnsureCallbackPriority(callback);
var objectInfo = objectInfoMap.get(object);
if (IS_UNDEFINED(objectInfo)) {
return ObjectUnobserve(object, callback);
}
+function EnqueueToCallback(callback, changeRecord) {
+ var callbackInfo = NormalizeCallbackInfo(callback);
+ observationState.pendingObservers[callbackInfo.priority] = callback;
+ callbackInfo.push(changeRecord);
+ %SetObserverDeliveryPending();
+}
+
function EnqueueChangeRecord(changeRecord, observers) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(changeRecord.name)) return;
if (IS_UNDEFINED(observer.accept[changeRecord.type]))
continue;
- var callback = observer.callback;
- var observerInfo = observerInfoMap.get(callback);
- observationState.pendingObservers[observerInfo.priority] = callback;
- %SetObserverDeliveryPending();
- if (IS_NULL(observerInfo.pendingChangeRecords)) {
- observerInfo.pendingChangeRecords = new InternalArray(changeRecord);
- } else {
- observerInfo.pendingChangeRecords.push(changeRecord);
- }
+ EnqueueToCallback(observer.callback, changeRecord);
}
}
return objectInfo.notifier;
}
-function DeliverChangeRecordsForObserver(observer) {
- var observerInfo = observerInfoMap.get(observer);
- if (IS_UNDEFINED(observerInfo))
+function CallbackDeliverPending(callback) {
+ var callbackInfo = callbackInfoMap.get(callback);
+ if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
return false;
- var pendingChangeRecords = observerInfo.pendingChangeRecords;
- if (IS_NULL(pendingChangeRecords))
- return false;
+ // Clear the pending change records from callback and return it to its
+ // "optimized" state.
+ var priority = callbackInfo.priority;
+ callbackInfoMap.set(callback, priority);
- observerInfo.pendingChangeRecords = null;
- delete observationState.pendingObservers[observerInfo.priority];
+ delete observationState.pendingObservers[priority];
var delivered = [];
- %MoveArrayContents(pendingChangeRecords, delivered);
+ %MoveArrayContents(callbackInfo, delivered);
+
try {
- %Call(void 0, delivered, observer);
+ %Call(void 0, delivered, callback);
} catch (ex) {}
return true;
}
if (!IS_SPEC_FUNCTION(callback))
throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]);
- while (DeliverChangeRecordsForObserver(callback)) {}
+ while (CallbackDeliverPending(callback)) {}
}
function DeliverChangeRecords() {
var pendingObservers = observationState.pendingObservers;
observationState.pendingObservers = new InternalArray;
for (var i in pendingObservers) {
- DeliverChangeRecordsForObserver(pendingObservers[i]);
+ CallbackDeliverPending(pendingObservers[i]);
}
}
}
"obj = null;");
i::Handle<i::JSObject> observation_state =
i::Isolate::Current()->factory()->observation_state();
- i::Handle<i::JSWeakMap> observerInfoMap =
+ i::Handle<i::JSWeakMap> callbackInfoMap =
i::Handle<i::JSWeakMap>::cast(
- i::GetProperty(observation_state, "observerInfoMap"));
+ i::GetProperty(observation_state, "callbackInfoMap"));
i::Handle<i::JSWeakMap> objectInfoMap =
i::Handle<i::JSWeakMap>::cast(
i::GetProperty(observation_state, "objectInfoMap"));
i::Handle<i::JSWeakMap> notifierTargetMap =
i::Handle<i::JSWeakMap>::cast(
i::GetProperty(observation_state, "notifierTargetMap"));
- CHECK_EQ(1, NumberOfElements(observerInfoMap));
+ CHECK_EQ(1, NumberOfElements(callbackInfoMap));
CHECK_EQ(1, NumberOfElements(objectInfoMap));
CHECK_EQ(1, NumberOfElements(notifierTargetMap));
HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
- CHECK_EQ(0, NumberOfElements(observerInfoMap));
+ CHECK_EQ(0, NumberOfElements(callbackInfoMap));
CHECK_EQ(0, NumberOfElements(objectInfoMap));
CHECK_EQ(0, NumberOfElements(notifierTargetMap));
}