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

Side by Side Diff: src/object-observe.js

Issue 123523002: Minor Object.observe optimizations (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 11 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 | Annotate | Revision Log
« 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 return !IS_UNDEFINED(this.get(key)); 84 return !IS_UNDEFINED(this.get(key));
85 } 85 }
86 }; 86 };
87 87
88 var callbackInfoMap = 88 var callbackInfoMap =
89 new ObservationWeakMap(observationState.callbackInfoMap); 89 new ObservationWeakMap(observationState.callbackInfoMap);
90 var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap); 90 var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap);
91 var notifierObjectInfoMap = 91 var notifierObjectInfoMap =
92 new ObservationWeakMap(observationState.notifierObjectInfoMap); 92 new ObservationWeakMap(observationState.notifierObjectInfoMap);
93 93
94 function nullProtoObject() {
95 return { __proto__: null };
96 }
97
94 function TypeMapCreate() { 98 function TypeMapCreate() {
95 return { __proto__: null }; 99 return nullProtoObject();
96 } 100 }
97 101
98 function TypeMapAddType(typeMap, type, ignoreDuplicate) { 102 function TypeMapAddType(typeMap, type, ignoreDuplicate) {
99 typeMap[type] = ignoreDuplicate ? 1 : (typeMap[type] || 0) + 1; 103 typeMap[type] = ignoreDuplicate ? 1 : (typeMap[type] || 0) + 1;
100 } 104 }
101 105
102 function TypeMapRemoveType(typeMap, type) { 106 function TypeMapRemoveType(typeMap, type) {
103 typeMap[type]--; 107 typeMap[type]--;
104 } 108 }
105 109
(...skipping 29 matching lines...) Expand all
135 'reconfigure', 139 'reconfigure',
136 'preventExtensions' 140 'preventExtensions'
137 ]); 141 ]);
138 142
139 // An Observer is a registration to observe an object by a callback with 143 // An Observer is a registration to observe an object by a callback with
140 // a given set of accept types. If the set of accept types is the default 144 // a given set of accept types. If the set of accept types is the default
141 // set for Object.observe, the observer is represented as a direct reference 145 // set for Object.observe, the observer is represented as a direct reference
142 // to the callback. An observer never changes its accept types and thus never 146 // to the callback. An observer never changes its accept types and thus never
143 // needs to "normalize". 147 // needs to "normalize".
144 function ObserverCreate(callback, acceptList) { 148 function ObserverCreate(callback, acceptList) {
145 return IS_UNDEFINED(acceptList) ? callback : { 149 if (IS_UNDEFINED(acceptList))
146 __proto__: null, 150 return callback;
147 callback: callback, 151 var observer = nullProtoObject();
148 accept: TypeMapCreateFromList(acceptList) 152 observer.callback = callback;
149 }; 153 observer.accept = TypeMapCreateFromList(acceptList);
154 return observer;
150 } 155 }
151 156
152 function ObserverGetCallback(observer) { 157 function ObserverGetCallback(observer) {
153 return IS_SPEC_FUNCTION(observer) ? observer : observer.callback; 158 return IS_SPEC_FUNCTION(observer) ? observer : observer.callback;
154 } 159 }
155 160
156 function ObserverGetAcceptTypes(observer) { 161 function ObserverGetAcceptTypes(observer) {
157 return IS_SPEC_FUNCTION(observer) ? defaultAcceptTypes : observer.accept; 162 return IS_SPEC_FUNCTION(observer) ? defaultAcceptTypes : observer.accept;
158 } 163 }
159 164
160 function ObserverIsActive(observer, objectInfo) { 165 function ObserverIsActive(observer, objectInfo) {
161 return TypeMapIsDisjointFrom(ObjectInfoGetPerformingTypes(objectInfo), 166 return TypeMapIsDisjointFrom(ObjectInfoGetPerformingTypes(objectInfo),
162 ObserverGetAcceptTypes(observer)); 167 ObserverGetAcceptTypes(observer));
163 } 168 }
164 169
165 function ObjectInfoGet(object) { 170 function ObjectInfoGetOrCreate(object) {
166 var objectInfo = objectInfoMap.get(object); 171 var objectInfo = ObjectInfoGet(object);
167 if (IS_UNDEFINED(objectInfo)) { 172 if (IS_UNDEFINED(objectInfo)) {
168 if (!%IsJSProxy(object)) 173 if (!%IsJSProxy(object))
169 %SetIsObserved(object); 174 %SetIsObserved(object);
170 175
171 objectInfo = { 176 objectInfo = {
172 object: object, 177 object: object,
173 changeObservers: null, 178 changeObservers: null,
174 notifier: null, 179 notifier: null,
175 performing: null, 180 performing: null,
176 performingCount: 0, 181 performingCount: 0,
177 }; 182 };
178 objectInfoMap.set(object, objectInfo); 183 objectInfoMap.set(object, objectInfo);
179 } 184 }
180 return objectInfo; 185 return objectInfo;
181 } 186 }
182 187
188 function ObjectInfoGet(object) {
189 return objectInfoMap.get(object);
190 }
191
183 function ObjectInfoGetFromNotifier(notifier) { 192 function ObjectInfoGetFromNotifier(notifier) {
184 return notifierObjectInfoMap.get(notifier); 193 return notifierObjectInfoMap.get(notifier);
185 } 194 }
186 195
187 function ObjectInfoGetNotifier(objectInfo) { 196 function ObjectInfoGetNotifier(objectInfo) {
188 if (IS_NULL(objectInfo.notifier)) { 197 if (IS_NULL(objectInfo.notifier)) {
189 objectInfo.notifier = { __proto__: notifierPrototype }; 198 objectInfo.notifier = { __proto__: notifierPrototype };
190 notifierObjectInfoMap.set(objectInfo.notifier, objectInfo); 199 notifierObjectInfoMap.set(objectInfo.notifier, objectInfo);
191 } 200 }
192 201
(...skipping 12 matching lines...) Expand all
205 // The set of observers on an object is called 'changeObservers'. The first 214 // The set of observers on an object is called 'changeObservers'. The first
206 // observer is referenced directly via objectInfo.changeObservers. When a second 215 // observer is referenced directly via objectInfo.changeObservers. When a second
207 // is added, changeObservers "normalizes" to become a mapping of callback 216 // is added, changeObservers "normalizes" to become a mapping of callback
208 // priority -> observer and is then stored on objectInfo.changeObservers. 217 // priority -> observer and is then stored on objectInfo.changeObservers.
209 function ObjectInfoNormalizeChangeObservers(objectInfo) { 218 function ObjectInfoNormalizeChangeObservers(objectInfo) {
210 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { 219 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
211 var observer = objectInfo.changeObservers; 220 var observer = objectInfo.changeObservers;
212 var callback = ObserverGetCallback(observer); 221 var callback = ObserverGetCallback(observer);
213 var callbackInfo = CallbackInfoGet(callback); 222 var callbackInfo = CallbackInfoGet(callback);
214 var priority = CallbackInfoGetPriority(callbackInfo); 223 var priority = CallbackInfoGetPriority(callbackInfo);
215 objectInfo.changeObservers = { __proto__: null }; 224 objectInfo.changeObservers = nullProtoObject();
216 objectInfo.changeObservers[priority] = observer; 225 objectInfo.changeObservers[priority] = observer;
217 } 226 }
218 } 227 }
219 228
220 function ObjectInfoAddObserver(objectInfo, callback, acceptList) { 229 function ObjectInfoAddObserver(objectInfo, callback, acceptList) {
221 var callbackInfo = CallbackInfoGetOrCreate(callback); 230 var callbackInfo = CallbackInfoGetOrCreate(callback);
222 var observer = ObserverCreate(callback, acceptList); 231 var observer = ObserverCreate(callback, acceptList);
223 232
224 if (!objectInfo.changeObservers) { 233 if (!objectInfo.changeObservers) {
225 objectInfo.changeObservers = observer; 234 objectInfo.changeObservers = observer;
(...skipping 10 matching lines...) Expand all
236 return; 245 return;
237 246
238 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { 247 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
239 if (callback === ObserverGetCallback(objectInfo.changeObservers)) 248 if (callback === ObserverGetCallback(objectInfo.changeObservers))
240 objectInfo.changeObservers = null; 249 objectInfo.changeObservers = null;
241 return; 250 return;
242 } 251 }
243 252
244 var callbackInfo = CallbackInfoGet(callback); 253 var callbackInfo = CallbackInfoGet(callback);
245 var priority = CallbackInfoGetPriority(callbackInfo); 254 var priority = CallbackInfoGetPriority(callbackInfo);
246 delete objectInfo.changeObservers[priority]; 255 objectInfo.changeObservers[priority] = null;
247 } 256 }
248 257
249 function ObjectInfoHasActiveObservers(objectInfo) { 258 function ObjectInfoHasActiveObservers(objectInfo) {
250 if (IS_UNDEFINED(objectInfo) || !objectInfo.changeObservers) 259 if (IS_UNDEFINED(objectInfo) || !objectInfo.changeObservers)
251 return false; 260 return false;
252 261
253 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) 262 if (ChangeObserversIsOptimized(objectInfo.changeObservers))
254 return ObserverIsActive(objectInfo.changeObservers, objectInfo); 263 return ObserverIsActive(objectInfo.changeObservers, objectInfo);
255 264
256 for (var priority in objectInfo.changeObservers) { 265 for (var priority in objectInfo.changeObservers) {
257 if (ObserverIsActive(objectInfo.changeObservers[priority], objectInfo)) 266 var observer = objectInfo.changeObservers[priority];
267 if (!observer)
adamk 2014/01/03 01:00:32 Not sure how much is matters, but this could be IS
rossberg 2014/01/07 17:27:00 Yes, please use IS_NULL. Also, you can just merge
rafaelw 2014/01/07 20:16:14 Done.
268 continue;
269 if (ObserverIsActive(observer, objectInfo))
258 return true; 270 return true;
259 } 271 }
260 272
261 return false; 273 return false;
262 } 274 }
263 275
264 function ObjectInfoAddPerformingType(objectInfo, type) { 276 function ObjectInfoAddPerformingType(objectInfo, type) {
265 objectInfo.performing = objectInfo.performing || TypeMapCreate(); 277 objectInfo.performing = objectInfo.performing || TypeMapCreate();
266 TypeMapAddType(objectInfo.performing, type); 278 TypeMapAddType(objectInfo.performing, type);
267 objectInfo.performingCount++; 279 objectInfo.performingCount++;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 function ObjectObserve(object, callback, acceptList) { 338 function ObjectObserve(object, callback, acceptList) {
327 if (!IS_SPEC_OBJECT(object)) 339 if (!IS_SPEC_OBJECT(object))
328 throw MakeTypeError("observe_non_object", ["observe"]); 340 throw MakeTypeError("observe_non_object", ["observe"]);
329 if (!IS_SPEC_FUNCTION(callback)) 341 if (!IS_SPEC_FUNCTION(callback))
330 throw MakeTypeError("observe_non_function", ["observe"]); 342 throw MakeTypeError("observe_non_function", ["observe"]);
331 if (ObjectIsFrozen(callback)) 343 if (ObjectIsFrozen(callback))
332 throw MakeTypeError("observe_callback_frozen"); 344 throw MakeTypeError("observe_callback_frozen");
333 if (!AcceptArgIsValid(acceptList)) 345 if (!AcceptArgIsValid(acceptList))
334 throw MakeTypeError("observe_accept_invalid"); 346 throw MakeTypeError("observe_accept_invalid");
335 347
336 var objectInfo = ObjectInfoGet(object); 348 var objectInfo = ObjectInfoGetOrCreate(object);
337 ObjectInfoAddObserver(objectInfo, callback, acceptList); 349 ObjectInfoAddObserver(objectInfo, callback, acceptList);
338 return object; 350 return object;
339 } 351 }
340 352
341 function ObjectUnobserve(object, callback) { 353 function ObjectUnobserve(object, callback) {
342 if (!IS_SPEC_OBJECT(object)) 354 if (!IS_SPEC_OBJECT(object))
343 throw MakeTypeError("observe_non_object", ["unobserve"]); 355 throw MakeTypeError("observe_non_object", ["unobserve"]);
344 if (!IS_SPEC_FUNCTION(callback)) 356 if (!IS_SPEC_FUNCTION(callback))
345 throw MakeTypeError("observe_non_function", ["unobserve"]); 357 throw MakeTypeError("observe_non_function", ["unobserve"]);
346 358
347 var objectInfo = objectInfoMap.get(object); 359 var objectInfo = ObjectInfoGet(object);
348 if (IS_UNDEFINED(objectInfo)) 360 if (IS_UNDEFINED(objectInfo))
349 return object; 361 return object;
350 362
351 ObjectInfoRemoveObserver(objectInfo, callback); 363 ObjectInfoRemoveObserver(objectInfo, callback);
352 return object; 364 return object;
353 } 365 }
354 366
355 function ArrayObserve(object, callback) { 367 function ArrayObserve(object, callback) {
356 return ObjectObserve(object, callback, ['add', 368 return ObjectObserve(object, callback, ['add',
357 'update', 369 'update',
(...skipping 16 matching lines...) Expand all
374 if (needsAccessCheck && 386 if (needsAccessCheck &&
375 // Drop all splice records on the floor for access-checked objects 387 // Drop all splice records on the floor for access-checked objects
376 (changeRecord.type == 'splice' || 388 (changeRecord.type == 'splice' ||
377 !%IsAccessAllowedForObserver( 389 !%IsAccessAllowedForObserver(
378 callback, changeRecord.object, changeRecord.name))) { 390 callback, changeRecord.object, changeRecord.name))) {
379 return; 391 return;
380 } 392 }
381 393
382 var callbackInfo = CallbackInfoNormalize(callback); 394 var callbackInfo = CallbackInfoNormalize(callback);
383 if (!observationState.pendingObservers) 395 if (!observationState.pendingObservers)
384 observationState.pendingObservers = { __proto__: null }; 396 observationState.pendingObservers = nullProtoObject();
385 observationState.pendingObservers[callbackInfo.priority] = callback; 397 observationState.pendingObservers[callbackInfo.priority] = callback;
386 callbackInfo.push(changeRecord); 398 callbackInfo.push(changeRecord);
387 %SetMicrotaskPending(true); 399 %SetMicrotaskPending(true);
388 } 400 }
389 401
390 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) { 402 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) {
391 if (!ObjectInfoHasActiveObservers(objectInfo)) 403 if (!ObjectInfoHasActiveObservers(objectInfo))
392 return; 404 return;
393 405
394 var hasType = !IS_UNDEFINED(type); 406 var hasType = !IS_UNDEFINED(type);
(...skipping 22 matching lines...) Expand all
417 429
418 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { 430 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
419 var observer = objectInfo.changeObservers; 431 var observer = objectInfo.changeObservers;
420 ObserverEnqueueIfActive(observer, objectInfo, changeRecord, 432 ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
421 needsAccessCheck); 433 needsAccessCheck);
422 return; 434 return;
423 } 435 }
424 436
425 for (var priority in objectInfo.changeObservers) { 437 for (var priority in objectInfo.changeObservers) {
426 var observer = objectInfo.changeObservers[priority]; 438 var observer = objectInfo.changeObservers[priority];
439 if (!observer)
adamk 2014/01/03 01:00:32 Ditto
rafaelw 2014/01/07 20:16:14 Done.
440 continue;
427 ObserverEnqueueIfActive(observer, objectInfo, changeRecord, 441 ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
428 needsAccessCheck); 442 needsAccessCheck);
429 } 443 }
430 } 444 }
431 445
432 function BeginPerformSplice(array) { 446 function BeginPerformSplice(array) {
433 var objectInfo = objectInfoMap.get(array); 447 var objectInfo = ObjectInfoGet(array);
434 if (!IS_UNDEFINED(objectInfo)) 448 if (!IS_UNDEFINED(objectInfo))
435 ObjectInfoAddPerformingType(objectInfo, 'splice'); 449 ObjectInfoAddPerformingType(objectInfo, 'splice');
436 } 450 }
437 451
438 function EndPerformSplice(array) { 452 function EndPerformSplice(array) {
439 var objectInfo = objectInfoMap.get(array); 453 var objectInfo = ObjectInfoGet(array);
440 if (!IS_UNDEFINED(objectInfo)) 454 if (!IS_UNDEFINED(objectInfo))
441 ObjectInfoRemovePerformingType(objectInfo, 'splice'); 455 ObjectInfoRemovePerformingType(objectInfo, 'splice');
442 } 456 }
443 457
444 function EnqueueSpliceRecord(array, index, removed, addedCount) { 458 function EnqueueSpliceRecord(array, index, removed, addedCount) {
445 var objectInfo = objectInfoMap.get(array); 459 var objectInfo = ObjectInfoGet(array);
446 if (!ObjectInfoHasActiveObservers(objectInfo)) 460 if (!ObjectInfoHasActiveObservers(objectInfo))
447 return; 461 return;
448 462
449 var changeRecord = { 463 var changeRecord = {
450 type: 'splice', 464 type: 'splice',
451 object: array, 465 object: array,
452 index: index, 466 index: index,
453 removed: removed, 467 removed: removed,
454 addedCount: addedCount 468 addedCount: addedCount
455 }; 469 };
456 470
457 ObjectFreeze(changeRecord); 471 ObjectFreeze(changeRecord);
458 ObjectFreeze(changeRecord.removed); 472 ObjectFreeze(changeRecord.removed);
459 ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord); 473 ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
460 } 474 }
461 475
462 function NotifyChange(type, object, name, oldValue) { 476 function NotifyChange(type, object, name, oldValue) {
463 var objectInfo = objectInfoMap.get(object); 477 var objectInfo = ObjectInfoGet(object);
464 if (!ObjectInfoHasActiveObservers(objectInfo)) 478 if (!ObjectInfoHasActiveObservers(objectInfo))
465 return; 479 return;
466 480
467 var changeRecord; 481 var changeRecord;
468 if (arguments.length == 2) { 482 if (arguments.length == 2) {
469 changeRecord = { type: type, object: object }; 483 changeRecord = { type: type, object: object };
470 } else if (arguments.length == 3) { 484 } else if (arguments.length == 3) {
471 changeRecord = { type: type, object: object, name: name }; 485 changeRecord = { type: type, object: object, name: name };
472 } else { 486 } else {
473 changeRecord = { 487 changeRecord = {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 if (IS_SPEC_OBJECT(changeRecord)) 536 if (IS_SPEC_OBJECT(changeRecord))
523 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType); 537 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType);
524 } 538 }
525 539
526 function ObjectGetNotifier(object) { 540 function ObjectGetNotifier(object) {
527 if (!IS_SPEC_OBJECT(object)) 541 if (!IS_SPEC_OBJECT(object))
528 throw MakeTypeError("observe_non_object", ["getNotifier"]); 542 throw MakeTypeError("observe_non_object", ["getNotifier"]);
529 543
530 if (ObjectIsFrozen(object)) return null; 544 if (ObjectIsFrozen(object)) return null;
531 545
532 var objectInfo = ObjectInfoGet(object); 546 var objectInfo = ObjectInfoGetOrCreate(object);
533 return ObjectInfoGetNotifier(objectInfo); 547 return ObjectInfoGetNotifier(objectInfo);
534 } 548 }
535 549
536 function CallbackDeliverPending(callback) { 550 function CallbackDeliverPending(callback) {
537 var callbackInfo = callbackInfoMap.get(callback); 551 var callbackInfo = callbackInfoMap.get(callback);
538 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo)) 552 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
539 return false; 553 return false;
540 554
541 // Clear the pending change records from callback and return it to its 555 // Clear the pending change records from callback and return it to its
542 // "optimized" state. 556 // "optimized" state.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 "observe", ArrayObserve, 599 "observe", ArrayObserve,
586 "unobserve", ArrayUnobserve 600 "unobserve", ArrayUnobserve
587 )); 601 ));
588 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( 602 InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
589 "notify", ObjectNotifierNotify, 603 "notify", ObjectNotifierNotify,
590 "performChange", ObjectNotifierPerformChange 604 "performChange", ObjectNotifierPerformChange
591 )); 605 ));
592 } 606 }
593 607
594 SetupObjectObserve(); 608 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