From 902a05922b07eab5348ca6987e41a7a97c067ea9 Mon Sep 17 00:00:00 2001 From: "rafaelw@chromium.org" Date: Wed, 8 Jan 2014 20:25:08 +0000 Subject: [PATCH] Minor Object.observe optimizations This patch includes the follow two minor optimizations: 1) When Object.unobserve-ing, instead of deleting from changeObservers, set the index position to null, and null-check when iterating elsewhere 2) Isolate creation of null-proto objects inside a utility function These former (deleting) was clearly showing up in d8 --prof traces and the later was preventing optimization of containing functions because of non-standard literal. Combined, on MDV construction/teardown benchmark, saves about 10%. Note that this patch also cleans up retrieving objectInfo inside a utility function. R=rossberg@chromium.org, rossberg BUG= Review URL: https://codereview.chromium.org/123523002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@18501 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/object-observe.js | 50 +++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/object-observe.js b/src/object-observe.js index dfa57b8312..499b27eca1 100644 --- a/src/object-observe.js +++ b/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; } @@ -142,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) { @@ -162,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); @@ -180,6 +185,10 @@ function ObjectInfoGet(object) { return objectInfo; } +function ObjectInfoGet(object) { + return objectInfoMap.get(object); +} + function ObjectInfoGetFromNotifier(notifier) { return notifierObjectInfoMap.get(notifier); } @@ -212,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; } } @@ -243,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) { @@ -254,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; } @@ -333,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; } @@ -344,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; @@ -381,7 +391,7 @@ function ObserverEnqueueIfActive(observer, objectInfo, changeRecord, var callbackInfo = CallbackInfoNormalize(callback); if (!observationState.pendingObservers) - observationState.pendingObservers = { __proto__: null }; + observationState.pendingObservers = nullProtoObject(); observationState.pendingObservers[callbackInfo.priority] = callback; callbackInfo.push(changeRecord); %SetMicrotaskPending(true); @@ -424,25 +434,27 @@ function ObjectInfoEnqueueInternalChangeRecord(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; @@ -460,7 +472,7 @@ function EnqueueSpliceRecord(array, index, removed, addedCount) { } function NotifyChange(type, object, name, oldValue) { - var objectInfo = objectInfoMap.get(object); + var objectInfo = ObjectInfoGet(object); if (!ObjectInfoHasActiveObservers(objectInfo)) return; @@ -529,7 +541,7 @@ function ObjectGetNotifier(object) { if (ObjectIsFrozen(object)) return null; - var objectInfo = ObjectInfoGet(object); + var objectInfo = ObjectInfoGetOrCreate(object); return ObjectInfoGetNotifier(objectInfo); }