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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 new ObservationWeakMap(observationState.callbackInfoMap); 60 new ObservationWeakMap(observationState.callbackInfoMap);
61 var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap); 61 var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
62 var notifierTargetMap = 62 var notifierTargetMap =
63 new ObservationWeakMap(observationState.notifierTargetMap); 63 new ObservationWeakMap(observationState.notifierTargetMap);
64 64
65 function CreateObjectInfo(object) { 65 function CreateObjectInfo(object) {
66 var info = { 66 var info = {
67 changeObservers: new InternalArray, 67 changeObservers: new InternalArray,
68 notifier: null, 68 notifier: null,
69 inactiveObservers: new InternalArray, 69 inactiveObservers: new InternalArray,
70 performing: { __proto__: null }, 70 performing: 0,
71 performingCount: 0, 71 performingCount: 0,
72 }; 72 };
73 objectInfoMap.set(object, info); 73 objectInfoMap.set(object, info);
74 return info; 74 return info;
75 } 75 }
76 76
77 var defaultAcceptTypes = { 77 var typeConstants = { __proto__: null };
78 __proto__: null, 78 var nextTypeConstant = 1;
79 'new': true, 79 var MAX_BITFIELD_CONSTANT = 1 << 30;
80 'updated': true,
81 'deleted': true,
82 'prototype': true,
83 'reconfigured': true
84 };
85 80
86 function CreateObserver(callback, accept) { 81 function NormalizeTypeMap(typeMap) {
87 var observer = { 82 if (IS_NUMBER(typeMap)) {
83 var bitfield = typeMap;
84 var typeMap = [];
85 var constant = 1;
86 while (true) {
87 if (bitfield & constant)
88 typeMap[constant] = 1;
89 if (constant == MAX_BITFIELD_CONSTANT)
90 break;
91 constant = constant << 1;
92 }
93 }
94
95 return typeMap;
96 }
97
98 function GetTypeConstant(type) {
99 var constant = typeConstants[type];
100 if (!constant) {
101 constant = nextTypeConstant;
102 typeConstants[type] = constant;
103 nextTypeConstant = nextTypeConstant < MAX_BITFIELD_CONSTANT ?
104 nextTypeConstant << 1 : nextTypeConstant + 1;
105 }
106
107 return constant;
108 }
109
110 function AddToTypeMap(typeMap, type, ignoreDuplicate) {
111 var typeConstant = GetTypeConstant(type);
112 if (IS_NUMBER(typeMap) &&
113 typeConstant <= MAX_BITFIELD_CONSTANT &&
114 (ignoreDuplicate || !(typeMap & typeConstant))) {
115 typeMap |= typeConstant;
116 return typeMap;
117 }
118
119 typeMap = NormalizeTypeMap(typeMap);
120 var value = ignoreDuplicate ? 1 : (typeMap[typeConstant] || 0) + 1;
121 typeMap[typeConstant] = value;
122 return typeMap;
123 }
124
125 function RemoveFromTypeMap(typeMap, type) {
126 var typeConstant = GetTypeConstant(type);
127 if (IS_NUMBER(typeMap)) {
128 if (typeConstant <= MAX_BITFIELD_CONSTANT && (typeMap & typeConstant))
129 typeMap -= typeConstant;
130 } else if (typeMap[typeConstant] > 0) {
131 typeMap[typeConstant]--;
132 }
133
134 return typeMap;
135 }
136
137 function CreateTypeMap(typeList) {
138 var typeMap = 0;
139 for (var i = 0; i < typeList.length; i++) {
140 typeMap = AddToTypeMap(typeMap, typeList[i], true);
141 }
142
143 return typeMap;
144 }
145
146 function TypeMapHasType(typeMap, type) {
147 return TypeMapHasConstant(typeMap, GetTypeConstant(type));
148 }
149
150 function TypeMapHasConstant(typeMap, constant) {
151 if (IS_NUMBER(typeMap))
152 return constant > MAX_BITFIELD_CONSTANT ? false : typeMap & constant;
153 else
154 return typeMap[constant] > 0;
155 }
156
157 function TypeMapsIntersect(typeMap1, typeMap2) {
158 if (IS_NUMBER(typeMap1) && IS_NUMBER(typeMap2))
159 return typeMap1 & typeMap2;
160
161 var checkMap = IS_NUMBER(typeMap1) ? typeMap1 : typeMap2;
162 var iterateMap = IS_NUMBER(typeMap1) ? typeMap2 : typeMap1;
163
164 for (var constant in iterateMap) {
165 if (TypeMapHasConstant(checkMap, constant))
166 return true;
167 }
168
169 return false;
170 }
171
172 var defaultAcceptTypes = CreateTypeMap([
173 'new',
174 'updated',
175 'deleted',
176 'prototype',
177 'reconfigured'
178 ]);
179
180 GetTypeConstant('splice');
181
182
183 function CreateObserver(callback, acceptList) {
184 return {
88 __proto__: null, 185 __proto__: null,
89 callback: callback, 186 callback: callback,
90 accept: defaultAcceptTypes 187 acceptMap: IS_UNDEFINED(acceptList) ?
188 defaultAcceptTypes : CreateTypeMap(acceptList)
91 }; 189 };
92
93 if (IS_UNDEFINED(accept))
94 return observer;
95
96 var acceptMap = { __proto__: null };
97 for (var i = 0; i < accept.length; i++)
98 acceptMap[accept[i]] = true;
99
100 observer.accept = acceptMap;
101 return observer;
102 } 190 }
103 191
104 function ObserverIsActive(observer, objectInfo) { 192 function ObserverIsActive(observer, objectInfo) {
105 if (objectInfo.performingCount === 0) 193 return objectInfo.performingCount === 0 ?
106 return true; 194 true : !TypeMapsIntersect(objectInfo.performing, observer.acceptMap);
107
108 var performing = objectInfo.performing;
109 for (var type in performing) {
110 if (performing[type] > 0 && observer.accept[type])
111 return false;
112 }
113
114 return true;
115 } 195 }
116 196
117 function ObserverIsInactive(observer, objectInfo) { 197 function ObserverIsInactive(observer, objectInfo) {
118 return !ObserverIsActive(observer, objectInfo); 198 return !ObserverIsActive(observer, objectInfo);
119 } 199 }
120 200
121 function RemoveNullElements(from) { 201 function RemoveNullElements(from) {
122 var i = 0; 202 var i = 0;
123 var j = 0; 203 var j = 0;
124 for (; i < from.length; i++) { 204 for (; i < from.length; i++) {
(...skipping 16 matching lines...) Expand all
141 anyRemoved = true; 221 anyRemoved = true;
142 from[i] = null; 222 from[i] = null;
143 to.push(observer); 223 to.push(observer);
144 } 224 }
145 } 225 }
146 226
147 if (anyRemoved) 227 if (anyRemoved)
148 RemoveNullElements(from); 228 RemoveNullElements(from);
149 } 229 }
150 230
231 function ObjectAddPerformingType(objectInfo, type) {
232 if (!objectInfo.performing) {
233 objectInfo.performing = AddToTypeMap(0, type);
234 objectInfo.performingCount = 1;
235 return true;
236 }
237
238 var hadType = TypeMapHasType(objectInfo.performing, type);
239 objectInfo.performing = AddToTypeMap(objectInfo.performing, type);
240 objectInfo.performingCount++;
241 return !hadType;
242 }
243
244 function ObjectRemovePerformingType(objectInfo, type) {
245 if (objectInfo.performingCount == 1) {
246 objectInfo.performing = 0;
247 objectInfo.performingCount = 0;
248 return true;
249 }
250
251 objectInfo.performing = RemoveFromTypeMap(objectInfo.performing, type);
252 objectInfo.performingCount--;
253 return !TypeMapHasType(objectInfo.performing, type);
254 }
255
151 function BeginPerformChange(objectInfo, type) { 256 function BeginPerformChange(objectInfo, type) {
152 objectInfo.performing[type] = (objectInfo.performing[type] || 0) + 1; 257 if (ObjectAddPerformingType(objectInfo, type)) {
153 objectInfo.performingCount++; 258 RepartitionObservers(ObserverIsInactive,
154 RepartitionObservers(ObserverIsInactive, 259 objectInfo.changeObservers,
155 objectInfo.changeObservers, 260 objectInfo.inactiveObservers,
156 objectInfo.inactiveObservers, 261 objectInfo);
157 objectInfo); 262 }
158 } 263 }
159 264
160 function EndPerformChange(objectInfo, type) { 265 function EndPerformChange(objectInfo, type) {
161 objectInfo.performing[type]--; 266 if (ObjectRemovePerformingType(objectInfo, type)) {
162 objectInfo.performingCount--; 267 RepartitionObservers(ObserverIsActive,
163 RepartitionObservers(ObserverIsActive, 268 objectInfo.inactiveObservers,
164 objectInfo.inactiveObservers, 269 objectInfo.changeObservers,
165 objectInfo.changeObservers, 270 objectInfo);
166 objectInfo); 271 }
167 } 272 }
168 273
169 function EnsureObserverRemoved(objectInfo, callback) { 274 function EnsureObserverRemoved(objectInfo, callback) {
170 function remove(observerList) { 275 function remove(observerList) {
171 for (var i = 0; i < observerList.length; i++) { 276 for (var i = 0; i < observerList.length; i++) {
172 if (observerList[i].callback === callback) { 277 if (observerList[i].callback === callback) {
173 observerList.splice(i, 1); 278 observerList.splice(i, 1);
174 return true; 279 return true;
175 } 280 }
176 } 281 }
(...skipping 30 matching lines...) Expand all
207 var callbackInfo = callbackInfoMap.get(callback); 312 var callbackInfo = callbackInfoMap.get(callback);
208 if (IS_NUMBER(callbackInfo)) { 313 if (IS_NUMBER(callbackInfo)) {
209 var priority = callbackInfo; 314 var priority = callbackInfo;
210 callbackInfo = new InternalArray; 315 callbackInfo = new InternalArray;
211 callbackInfo.priority = priority; 316 callbackInfo.priority = priority;
212 callbackInfoMap.set(callback, callbackInfo); 317 callbackInfoMap.set(callback, callbackInfo);
213 } 318 }
214 return callbackInfo; 319 return callbackInfo;
215 } 320 }
216 321
217 function ObjectObserve(object, callback, accept) { 322 function ObjectObserve(object, callback, acceptList) {
218 if (!IS_SPEC_OBJECT(object)) 323 if (!IS_SPEC_OBJECT(object))
219 throw MakeTypeError("observe_non_object", ["observe"]); 324 throw MakeTypeError("observe_non_object", ["observe"]);
220 if (!IS_SPEC_FUNCTION(callback)) 325 if (!IS_SPEC_FUNCTION(callback))
221 throw MakeTypeError("observe_non_function", ["observe"]); 326 throw MakeTypeError("observe_non_function", ["observe"]);
222 if (ObjectIsFrozen(callback)) 327 if (ObjectIsFrozen(callback))
223 throw MakeTypeError("observe_callback_frozen"); 328 throw MakeTypeError("observe_callback_frozen");
224 if (!AcceptArgIsValid(accept)) 329 if (!AcceptArgIsValid(acceptList))
225 throw MakeTypeError("observe_accept_invalid"); 330 throw MakeTypeError("observe_accept_invalid");
226 331
227 EnsureCallbackPriority(callback); 332 EnsureCallbackPriority(callback);
228 333
229 var objectInfo = objectInfoMap.get(object); 334 var objectInfo = objectInfoMap.get(object);
230 if (IS_UNDEFINED(objectInfo)) { 335 if (IS_UNDEFINED(objectInfo)) {
231 objectInfo = CreateObjectInfo(object); 336 objectInfo = CreateObjectInfo(object);
232 %SetIsObserved(object); 337 %SetIsObserved(object);
233 } 338 }
234 339
235 EnsureObserverRemoved(objectInfo, callback); 340 EnsureObserverRemoved(objectInfo, callback);
236 341
237 var observer = CreateObserver(callback, accept); 342 var observer = CreateObserver(callback, acceptList);
238 if (ObserverIsActive(observer, objectInfo)) 343 if (ObserverIsActive(observer, objectInfo))
239 objectInfo.changeObservers.push(observer); 344 objectInfo.changeObservers.push(observer);
240 else 345 else
241 objectInfo.inactiveObservers.push(observer); 346 objectInfo.inactiveObservers.push(observer);
242 347
243 return object; 348 return object;
244 } 349 }
245 350
246 function ObjectUnobserve(object, callback) { 351 function ObjectUnobserve(object, callback) {
247 if (!IS_SPEC_OBJECT(object)) 352 if (!IS_SPEC_OBJECT(object))
(...skipping 20 matching lines...) Expand all
268 return ObjectUnobserve(object, callback); 373 return ObjectUnobserve(object, callback);
269 } 374 }
270 375
271 function EnqueueToCallback(callback, changeRecord) { 376 function EnqueueToCallback(callback, changeRecord) {
272 var callbackInfo = NormalizeCallbackInfo(callback); 377 var callbackInfo = NormalizeCallbackInfo(callback);
273 observationState.pendingObservers[callbackInfo.priority] = callback; 378 observationState.pendingObservers[callbackInfo.priority] = callback;
274 callbackInfo.push(changeRecord); 379 callbackInfo.push(changeRecord);
275 %SetObserverDeliveryPending(); 380 %SetObserverDeliveryPending();
276 } 381 }
277 382
383 function ObserverAcceptsType(observer, type) {
384 return TypeMapHasType(observer.acceptMap, type);
385 }
386
278 function EnqueueChangeRecord(changeRecord, observers) { 387 function EnqueueChangeRecord(changeRecord, observers) {
279 // TODO(rossberg): adjust once there is a story for symbols vs proxies. 388 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
280 if (IS_SYMBOL(changeRecord.name)) return; 389 if (IS_SYMBOL(changeRecord.name)) return;
281 390
282 for (var i = 0; i < observers.length; i++) { 391 for (var i = 0; i < observers.length; i++) {
283 var observer = observers[i]; 392 var observer = observers[i];
284 if (IS_UNDEFINED(observer.accept[changeRecord.type])) 393 if (ObserverAcceptsType(observer, changeRecord.type))
285 continue; 394 EnqueueToCallback(observer.callback, changeRecord);
286
287 EnqueueToCallback(observer.callback, changeRecord);
288 } 395 }
289 } 396 }
290 397
291 function BeginPerformSplice(array) { 398 function BeginPerformSplice(array) {
292 var objectInfo = objectInfoMap.get(array); 399 var objectInfo = objectInfoMap.get(array);
293 if (!IS_UNDEFINED(objectInfo)) 400 if (!IS_UNDEFINED(objectInfo))
294 BeginPerformChange(objectInfo, 'splice'); 401 BeginPerformChange(objectInfo, 'splice');
295 } 402 }
296 403
297 function EndPerformSplice(array) { 404 function EndPerformSplice(array) {
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 "observe", ArrayObserve, 560 "observe", ArrayObserve,
454 "unobserve", ArrayUnobserve 561 "unobserve", ArrayUnobserve
455 )); 562 ));
456 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( 563 InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
457 "notify", ObjectNotifierNotify, 564 "notify", ObjectNotifierNotify,
458 "performChange", ObjectNotifierPerformChange 565 "performChange", ObjectNotifierPerformChange
459 )); 566 ));
460 } 567 }
461 568
462 SetupObjectObserve(); 569 SetupObjectObserve();
OLDNEW
« 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