Index: src/object-observe.js |
diff --git a/src/object-observe.js b/src/object-observe.js |
index 3f9af641f882e5a540f49f24c31147e49bf1de37..b598e685b436a40c80c5b540666dff770aed6caf 100644 |
--- a/src/object-observe.js |
+++ b/src/object-observe.js |
@@ -33,28 +33,83 @@ |
// implementation of (1) and (2) have "optimized" states which represent |
// common cases which can be handled more efficiently. |
-var observationState = %GetObservationState(); |
+var observationState; |
+ |
+function GetObservationStateJS() { |
+ if (IS_UNDEFINED(observationState)) |
+ observationState = %GetObservationState(); |
+ |
+ if (IS_UNDEFINED(observationState.callbackInfoMap)) { |
+ observationState.callbackInfoMap = %ObservationWeakMapCreate(); |
+ observationState.objectInfoMap = %ObservationWeakMapCreate(); |
+ observationState.notifierObjectInfoMap = %ObservationWeakMapCreate(); |
+ observationState.pendingObservers = null; |
+ observationState.nextCallbackPriority = 0; |
+ observationState.lastMicrotaskId = 0; |
+ } |
+ |
+ return observationState; |
+} |
+ |
+function GetWeakMapWrapper() { |
+ function MapWrapper(map) { |
+ this.map_ = map; |
+ }; |
+ |
+ MapWrapper.prototype = { |
+ __proto__: null, |
+ get: function(key) { |
+ return %WeakCollectionGet(this.map_, key); |
+ }, |
+ set: function(key, value) { |
+ %WeakCollectionSet(this.map_, key, value); |
+ }, |
+ has: function(key) { |
+ return !IS_UNDEFINED(this.get(key)); |
+ } |
+ }; |
+ |
+ return MapWrapper; |
+} |
+ |
+var contextMaps; |
+ |
+function GetContextMaps() { |
+ if (IS_UNDEFINED(contextMaps)) { |
+ var map = GetWeakMapWrapper(); |
+ var observationState = GetObservationStateJS(); |
+ contextMaps = { |
+ callbackInfoMap: new map(observationState.callbackInfoMap), |
+ objectInfoMap: new map(observationState.objectInfoMap), |
+ notifierObjectInfoMap: new map(observationState.notifierObjectInfoMap) |
+ }; |
+ } |
-// This is run during the first context creation in an isolate. |
-if (IS_UNDEFINED(observationState.callbackInfoMap)) { |
- observationState.callbackInfoMap = %ObservationWeakMapCreate(); |
- observationState.objectInfoMap = %ObservationWeakMapCreate(); |
- observationState.notifierObjectInfoMap = %ObservationWeakMapCreate(); |
- observationState.pendingObservers = null; |
- observationState.nextCallbackPriority = 0; |
- observationState.lastMicrotaskId = 0; |
+ return contextMaps; |
+} |
+ |
+function GetCallbackInfoMap() { |
+ return GetContextMaps().callbackInfoMap; |
+} |
+ |
+function GetObjectInfoMap() { |
+ return GetContextMaps().objectInfoMap; |
+} |
+ |
+function GetNotifierObjectInfoMap() { |
+ return GetContextMaps().notifierObjectInfoMap; |
} |
function GetPendingObservers() { |
- return observationState.pendingObservers; |
+ return GetObservationStateJS().pendingObservers; |
} |
function SetPendingObservers(pendingObservers) { |
- observationState.pendingObservers = pendingObservers; |
+ GetObservationStateJS().pendingObservers = pendingObservers; |
} |
function GetNextCallbackPriority() { |
- return observationState.nextCallbackPriority++; |
+ return GetObservationStateJS().nextCallbackPriority++; |
} |
function nullProtoObject() { |
@@ -149,32 +204,35 @@ function ObjectInfoGetOrCreate(object) { |
performing: null, |
performingCount: 0, |
}; |
- %WeakCollectionSet(observationState.objectInfoMap, object, objectInfo); |
+ GetObjectInfoMap().set(object, objectInfo); |
} |
return objectInfo; |
} |
function ObjectInfoGet(object) { |
- return %WeakCollectionGet(observationState.objectInfoMap, object); |
+ return GetObjectInfoMap().get(object); |
} |
function ObjectInfoGetFromNotifier(notifier) { |
- return %WeakCollectionGet(observationState.notifierObjectInfoMap, notifier); |
+ return GetNotifierObjectInfoMap().get(notifier); |
} |
function ObjectInfoGetNotifier(objectInfo) { |
if (IS_NULL(objectInfo.notifier)) { |
objectInfo.notifier = { __proto__: notifierPrototype }; |
- %WeakCollectionSet(observationState.notifierObjectInfoMap, |
- objectInfo.notifier, objectInfo); |
+ GetNotifierObjectInfoMap().set(objectInfo.notifier, objectInfo); |
} |
return objectInfo.notifier; |
} |
+function ObjectInfoGetObject(objectInfo) { |
+ return objectInfo.object; |
+} |
+ |
function ChangeObserversIsOptimized(changeObservers) { |
- return IS_SPEC_FUNCTION(changeObservers) || |
- IS_SPEC_FUNCTION(changeObservers.callback); |
+ return typeof changeObservers === 'function' || |
+ typeof changeObservers.callback === 'function'; |
} |
// The set of observers on an object is called 'changeObservers'. The first |
@@ -270,20 +328,16 @@ function ConvertAcceptListToTypeMap(arg) { |
// priority. When a change record must be enqueued for the callback, it |
// normalizes. When delivery clears any pending change records, it re-optimizes. |
function CallbackInfoGet(callback) { |
- return %WeakCollectionGet(observationState.callbackInfoMap, callback); |
-} |
- |
-function CallbackInfoSet(callback, callbackInfo) { |
- %WeakCollectionSet(observationState.callbackInfoMap, callback, callbackInfo); |
+ return GetCallbackInfoMap().get(callback); |
} |
function CallbackInfoGetOrCreate(callback) { |
- var callbackInfo = CallbackInfoGet(callback); |
+ var callbackInfo = GetCallbackInfoMap().get(callback); |
if (!IS_UNDEFINED(callbackInfo)) |
return callbackInfo; |
- var priority = GetNextCallbackPriority(); |
- CallbackInfoSet(callback, priority); |
+ var priority = GetNextCallbackPriority(); |
+ GetCallbackInfoMap().set(callback, priority); |
return priority; |
} |
@@ -295,12 +349,12 @@ function CallbackInfoGetPriority(callbackInfo) { |
} |
function CallbackInfoNormalize(callback) { |
- var callbackInfo = CallbackInfoGet(callback); |
+ var callbackInfo = GetCallbackInfoMap().get(callback); |
if (IS_NUMBER(callbackInfo)) { |
var priority = callbackInfo; |
callbackInfo = new InternalArray; |
callbackInfo.priority = priority; |
- CallbackInfoSet(callback, callbackInfo); |
+ GetCallbackInfoMap().set(callback, callbackInfo); |
} |
return callbackInfo; |
} |
@@ -369,7 +423,7 @@ function ObserverEnqueueIfActive(observer, objectInfo, changeRecord) { |
if (IS_NULL(GetPendingObservers())) { |
SetPendingObservers(nullProtoObject()); |
if (DEBUG_IS_ACTIVE) { |
- var id = ++observationState.lastMicrotaskId; |
+ var id = ++GetObservationStateJS().lastMicrotaskId; |
var name = "Object.observe"; |
%EnqueueMicrotask(function() { |
%DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name }); |
@@ -391,8 +445,8 @@ function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) { |
var hasType = !IS_UNDEFINED(type); |
var newRecord = hasType ? |
- { object: objectInfo.object, type: type } : |
- { object: objectInfo.object }; |
+ { object: ObjectInfoGetObject(objectInfo), type: type } : |
+ { object: ObjectInfoGetObject(objectInfo) }; |
for (var prop in changeRecord) { |
if (prop === 'object' || (hasType && prop === 'type')) continue; |
@@ -540,18 +594,17 @@ function NativeObjectGetNotifier(object) { |
} |
function CallbackDeliverPending(callback) { |
- var callbackInfo = CallbackInfoGet(callback); |
+ var callbackInfo = GetCallbackInfoMap().get(callback); |
if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo)) |
return false; |
// Clear the pending change records from callback and return it to its |
// "optimized" state. |
var priority = callbackInfo.priority; |
- CallbackInfoSet(callback, priority); |
+ GetCallbackInfoMap().set(callback, priority); |
- var pendingObservers = GetPendingObservers(); |
- if (!IS_NULL(pendingObservers)) |
- delete pendingObservers[priority]; |
+ if (GetPendingObservers()) |
+ delete GetPendingObservers()[priority]; |
var delivered = []; |
%MoveArrayContents(callbackInfo, delivered); |
@@ -571,7 +624,7 @@ function ObjectDeliverChangeRecords(callback) { |
function ObserveMicrotaskRunner() { |
var pendingObservers = GetPendingObservers(); |
- if (!IS_NULL(pendingObservers)) { |
+ if (pendingObservers) { |
SetPendingObservers(null); |
for (var i in pendingObservers) { |
CallbackDeliverPending(pendingObservers[i]); |