Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(550)

Unified Diff: src/object-observe.js

Issue 19269007: optimized TypeMap Base URL: https://github.com/v8/v8.git@bleeding_edge
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/object-observe.js
diff --git a/src/object-observe.js b/src/object-observe.js
index 1c147d95e30f9e82d45797d500b2d32bb198b064..c9b1c88363ae65524cfa878424c2feb2f77314d2 100644
--- a/src/object-observe.js
+++ b/src/object-observe.js
@@ -67,51 +67,131 @@ function CreateObjectInfo(object) {
changeObservers: new InternalArray,
notifier: null,
inactiveObservers: new InternalArray,
- performing: { __proto__: null },
+ performing: 0,
performingCount: 0,
};
objectInfoMap.set(object, info);
return info;
}
-var defaultAcceptTypes = {
- __proto__: null,
- 'new': true,
- 'updated': true,
- 'deleted': true,
- 'prototype': true,
- 'reconfigured': true
-};
+var typeConstants = { __proto__: null };
+var nextTypeConstant = 1;
+var MAX_BITFIELD_CONSTANT = 1 << 30;
+
+function NormalizeTypeMap(typeMap) {
+ if (IS_NUMBER(typeMap)) {
+ var bitfield = typeMap;
+ var typeMap = [];
+ var constant = 1;
+ while (true) {
+ if (bitfield & constant)
+ typeMap[constant] = 1;
+ if (constant == MAX_BITFIELD_CONSTANT)
+ break;
+ constant = constant << 1;
+ }
+ }
-function CreateObserver(callback, accept) {
- var observer = {
- __proto__: null,
- callback: callback,
- accept: defaultAcceptTypes
- };
+ return typeMap;
+}
- if (IS_UNDEFINED(accept))
- return observer;
+function GetTypeConstant(type) {
+ var constant = typeConstants[type];
+ if (!constant) {
+ constant = nextTypeConstant;
+ typeConstants[type] = constant;
+ nextTypeConstant = nextTypeConstant < MAX_BITFIELD_CONSTANT ?
+ nextTypeConstant << 1 : nextTypeConstant + 1;
+ }
- var acceptMap = { __proto__: null };
- for (var i = 0; i < accept.length; i++)
- acceptMap[accept[i]] = true;
+ return constant;
+}
+
+function AddToTypeMap(typeMap, type, ignoreDuplicate) {
+ var typeConstant = GetTypeConstant(type);
+ if (IS_NUMBER(typeMap) &&
+ typeConstant <= MAX_BITFIELD_CONSTANT &&
+ (ignoreDuplicate || !(typeMap & typeConstant))) {
+ typeMap |= typeConstant;
+ return typeMap;
+ }
- observer.accept = acceptMap;
- return observer;
+ typeMap = NormalizeTypeMap(typeMap);
+ var value = ignoreDuplicate ? 1 : (typeMap[typeConstant] || 0) + 1;
+ typeMap[typeConstant] = value;
+ return typeMap;
}
-function ObserverIsActive(observer, objectInfo) {
- if (objectInfo.performingCount === 0)
- return true;
+function RemoveFromTypeMap(typeMap, type) {
+ var typeConstant = GetTypeConstant(type);
+ if (IS_NUMBER(typeMap)) {
+ if (typeConstant <= MAX_BITFIELD_CONSTANT && (typeMap & typeConstant))
+ typeMap -= typeConstant;
+ } else if (typeMap[typeConstant] > 0) {
+ typeMap[typeConstant]--;
+ }
- var performing = objectInfo.performing;
- for (var type in performing) {
- if (performing[type] > 0 && observer.accept[type])
- return false;
+ return typeMap;
+}
+
+function CreateTypeMap(typeList) {
+ var typeMap = 0;
+ for (var i = 0; i < typeList.length; i++) {
+ typeMap = AddToTypeMap(typeMap, typeList[i], true);
}
- return true;
+ return typeMap;
+}
+
+function TypeMapHasType(typeMap, type) {
+ return TypeMapHasConstant(typeMap, GetTypeConstant(type));
+}
+
+function TypeMapHasConstant(typeMap, constant) {
+ if (IS_NUMBER(typeMap))
+ return constant > MAX_BITFIELD_CONSTANT ? false : typeMap & constant;
+ else
+ return typeMap[constant] > 0;
+}
+
+function TypeMapsIntersect(typeMap1, typeMap2) {
+ if (IS_NUMBER(typeMap1) && IS_NUMBER(typeMap2))
+ return typeMap1 & typeMap2;
+
+ var checkMap = IS_NUMBER(typeMap1) ? typeMap1 : typeMap2;
+ var iterateMap = IS_NUMBER(typeMap1) ? typeMap2 : typeMap1;
+
+ for (var constant in iterateMap) {
+ if (TypeMapHasConstant(checkMap, constant))
+ return true;
+ }
+
+ return false;
+}
+
+var defaultAcceptTypes = CreateTypeMap([
+ 'new',
+ 'updated',
+ 'deleted',
+ 'prototype',
+ 'reconfigured'
+]);
+
+GetTypeConstant('splice');
+
+
+function CreateObserver(callback, acceptList) {
+ return {
+ __proto__: null,
+ callback: callback,
+ acceptMap: IS_UNDEFINED(acceptList) ?
+ defaultAcceptTypes : CreateTypeMap(acceptList)
+ };
+}
+
+function ObserverIsActive(observer, objectInfo) {
+ return objectInfo.performingCount === 0 ?
+ true : !TypeMapsIntersect(objectInfo.performing, observer.acceptMap);
}
function ObserverIsInactive(observer, objectInfo) {
@@ -148,22 +228,47 @@ function RepartitionObservers(conditionFn, from, to, objectInfo) {
RemoveNullElements(from);
}
-function BeginPerformChange(objectInfo, type) {
- objectInfo.performing[type] = (objectInfo.performing[type] || 0) + 1;
+function ObjectAddPerformingType(objectInfo, type) {
+ if (!objectInfo.performing) {
+ objectInfo.performing = AddToTypeMap(0, type);
+ objectInfo.performingCount = 1;
+ return true;
+ }
+
+ var hadType = TypeMapHasType(objectInfo.performing, type);
+ objectInfo.performing = AddToTypeMap(objectInfo.performing, type);
objectInfo.performingCount++;
- RepartitionObservers(ObserverIsInactive,
- objectInfo.changeObservers,
- objectInfo.inactiveObservers,
- objectInfo);
+ return !hadType;
}
-function EndPerformChange(objectInfo, type) {
- objectInfo.performing[type]--;
+function ObjectRemovePerformingType(objectInfo, type) {
+ if (objectInfo.performingCount == 1) {
+ objectInfo.performing = 0;
+ objectInfo.performingCount = 0;
+ return true;
+ }
+
+ objectInfo.performing = RemoveFromTypeMap(objectInfo.performing, type);
objectInfo.performingCount--;
- RepartitionObservers(ObserverIsActive,
- objectInfo.inactiveObservers,
- objectInfo.changeObservers,
- objectInfo);
+ return !TypeMapHasType(objectInfo.performing, type);
+}
+
+function BeginPerformChange(objectInfo, type) {
+ if (ObjectAddPerformingType(objectInfo, type)) {
+ RepartitionObservers(ObserverIsInactive,
+ objectInfo.changeObservers,
+ objectInfo.inactiveObservers,
+ objectInfo);
+ }
+}
+
+function EndPerformChange(objectInfo, type) {
+ if (ObjectRemovePerformingType(objectInfo, type)) {
+ RepartitionObservers(ObserverIsActive,
+ objectInfo.inactiveObservers,
+ objectInfo.changeObservers,
+ objectInfo);
+ }
}
function EnsureObserverRemoved(objectInfo, callback) {
@@ -214,14 +319,14 @@ function NormalizeCallbackInfo(callback) {
return callbackInfo;
}
-function ObjectObserve(object, callback, accept) {
+function ObjectObserve(object, callback, acceptList) {
if (!IS_SPEC_OBJECT(object))
throw MakeTypeError("observe_non_object", ["observe"]);
if (!IS_SPEC_FUNCTION(callback))
throw MakeTypeError("observe_non_function", ["observe"]);
if (ObjectIsFrozen(callback))
throw MakeTypeError("observe_callback_frozen");
- if (!AcceptArgIsValid(accept))
+ if (!AcceptArgIsValid(acceptList))
throw MakeTypeError("observe_accept_invalid");
EnsureCallbackPriority(callback);
@@ -234,7 +339,7 @@ function ObjectObserve(object, callback, accept) {
EnsureObserverRemoved(objectInfo, callback);
- var observer = CreateObserver(callback, accept);
+ var observer = CreateObserver(callback, acceptList);
if (ObserverIsActive(observer, objectInfo))
objectInfo.changeObservers.push(observer);
else
@@ -275,16 +380,18 @@ function EnqueueToCallback(callback, changeRecord) {
%SetObserverDeliveryPending();
}
+function ObserverAcceptsType(observer, type) {
+ return TypeMapHasType(observer.acceptMap, type);
+}
+
function EnqueueChangeRecord(changeRecord, observers) {
// TODO(rossberg): adjust once there is a story for symbols vs proxies.
if (IS_SYMBOL(changeRecord.name)) return;
for (var i = 0; i < observers.length; i++) {
var observer = observers[i];
- if (IS_UNDEFINED(observer.accept[changeRecord.type]))
- continue;
-
- EnqueueToCallback(observer.callback, changeRecord);
+ if (ObserverAcceptsType(observer, changeRecord.type))
+ EnqueueToCallback(observer.callback, changeRecord);
}
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698