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

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: cr changes 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 (!IS_NULL(observer) && ObserverIsActive(observer, objectInfo))
258 return true; 268 return true;
259 } 269 }
260 270
261 return false; 271 return false;
262 } 272 }
263 273
264 function ObjectInfoAddPerformingType(objectInfo, type) { 274 function ObjectInfoAddPerformingType(objectInfo, type) {
265 objectInfo.performing = objectInfo.performing || TypeMapCreate(); 275 objectInfo.performing = objectInfo.performing || TypeMapCreate();
266 TypeMapAddType(objectInfo.performing, type); 276 TypeMapAddType(objectInfo.performing, type);
267 objectInfo.performingCount++; 277 objectInfo.performingCount++;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
326 function ObjectObserve(object, callback, acceptList) { 336 function ObjectObserve(object, callback, acceptList) {
327 if (!IS_SPEC_OBJECT(object)) 337 if (!IS_SPEC_OBJECT(object))
328 throw MakeTypeError("observe_non_object", ["observe"]); 338 throw MakeTypeError("observe_non_object", ["observe"]);
329 if (!IS_SPEC_FUNCTION(callback)) 339 if (!IS_SPEC_FUNCTION(callback))
330 throw MakeTypeError("observe_non_function", ["observe"]); 340 throw MakeTypeError("observe_non_function", ["observe"]);
331 if (ObjectIsFrozen(callback)) 341 if (ObjectIsFrozen(callback))
332 throw MakeTypeError("observe_callback_frozen"); 342 throw MakeTypeError("observe_callback_frozen");
333 if (!AcceptArgIsValid(acceptList)) 343 if (!AcceptArgIsValid(acceptList))
334 throw MakeTypeError("observe_accept_invalid"); 344 throw MakeTypeError("observe_accept_invalid");
335 345
336 var objectInfo = ObjectInfoGet(object); 346 var objectInfo = ObjectInfoGetOrCreate(object);
337 ObjectInfoAddObserver(objectInfo, callback, acceptList); 347 ObjectInfoAddObserver(objectInfo, callback, acceptList);
338 return object; 348 return object;
339 } 349 }
340 350
341 function ObjectUnobserve(object, callback) { 351 function ObjectUnobserve(object, callback) {
342 if (!IS_SPEC_OBJECT(object)) 352 if (!IS_SPEC_OBJECT(object))
343 throw MakeTypeError("observe_non_object", ["unobserve"]); 353 throw MakeTypeError("observe_non_object", ["unobserve"]);
344 if (!IS_SPEC_FUNCTION(callback)) 354 if (!IS_SPEC_FUNCTION(callback))
345 throw MakeTypeError("observe_non_function", ["unobserve"]); 355 throw MakeTypeError("observe_non_function", ["unobserve"]);
346 356
347 var objectInfo = objectInfoMap.get(object); 357 var objectInfo = ObjectInfoGet(object);
348 if (IS_UNDEFINED(objectInfo)) 358 if (IS_UNDEFINED(objectInfo))
349 return object; 359 return object;
350 360
351 ObjectInfoRemoveObserver(objectInfo, callback); 361 ObjectInfoRemoveObserver(objectInfo, callback);
352 return object; 362 return object;
353 } 363 }
354 364
355 function ArrayObserve(object, callback) { 365 function ArrayObserve(object, callback) {
356 return ObjectObserve(object, callback, ['add', 366 return ObjectObserve(object, callback, ['add',
357 'update', 367 'update',
(...skipping 16 matching lines...) Expand all
374 if (needsAccessCheck && 384 if (needsAccessCheck &&
375 // Drop all splice records on the floor for access-checked objects 385 // Drop all splice records on the floor for access-checked objects
376 (changeRecord.type == 'splice' || 386 (changeRecord.type == 'splice' ||
377 !%IsAccessAllowedForObserver( 387 !%IsAccessAllowedForObserver(
378 callback, changeRecord.object, changeRecord.name))) { 388 callback, changeRecord.object, changeRecord.name))) {
379 return; 389 return;
380 } 390 }
381 391
382 var callbackInfo = CallbackInfoNormalize(callback); 392 var callbackInfo = CallbackInfoNormalize(callback);
383 if (!observationState.pendingObservers) 393 if (!observationState.pendingObservers)
384 observationState.pendingObservers = { __proto__: null }; 394 observationState.pendingObservers = nullProtoObject();
385 observationState.pendingObservers[callbackInfo.priority] = callback; 395 observationState.pendingObservers[callbackInfo.priority] = callback;
386 callbackInfo.push(changeRecord); 396 callbackInfo.push(changeRecord);
387 %SetMicrotaskPending(true); 397 %SetMicrotaskPending(true);
388 } 398 }
389 399
390 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) { 400 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) {
391 if (!ObjectInfoHasActiveObservers(objectInfo)) 401 if (!ObjectInfoHasActiveObservers(objectInfo))
392 return; 402 return;
393 403
394 var hasType = !IS_UNDEFINED(type); 404 var hasType = !IS_UNDEFINED(type);
(...skipping 22 matching lines...) Expand all
417 427
418 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { 428 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
419 var observer = objectInfo.changeObservers; 429 var observer = objectInfo.changeObservers;
420 ObserverEnqueueIfActive(observer, objectInfo, changeRecord, 430 ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
421 needsAccessCheck); 431 needsAccessCheck);
422 return; 432 return;
423 } 433 }
424 434
425 for (var priority in objectInfo.changeObservers) { 435 for (var priority in objectInfo.changeObservers) {
426 var observer = objectInfo.changeObservers[priority]; 436 var observer = objectInfo.changeObservers[priority];
437 if (IS_NULL(observer))
438 continue;
427 ObserverEnqueueIfActive(observer, objectInfo, changeRecord, 439 ObserverEnqueueIfActive(observer, objectInfo, changeRecord,
428 needsAccessCheck); 440 needsAccessCheck);
429 } 441 }
430 } 442 }
431 443
432 function BeginPerformSplice(array) { 444 function BeginPerformSplice(array) {
433 var objectInfo = objectInfoMap.get(array); 445 var objectInfo = ObjectInfoGet(array);
434 if (!IS_UNDEFINED(objectInfo)) 446 if (!IS_UNDEFINED(objectInfo))
435 ObjectInfoAddPerformingType(objectInfo, 'splice'); 447 ObjectInfoAddPerformingType(objectInfo, 'splice');
436 } 448 }
437 449
438 function EndPerformSplice(array) { 450 function EndPerformSplice(array) {
439 var objectInfo = objectInfoMap.get(array); 451 var objectInfo = ObjectInfoGet(array);
440 if (!IS_UNDEFINED(objectInfo)) 452 if (!IS_UNDEFINED(objectInfo))
441 ObjectInfoRemovePerformingType(objectInfo, 'splice'); 453 ObjectInfoRemovePerformingType(objectInfo, 'splice');
442 } 454 }
443 455
444 function EnqueueSpliceRecord(array, index, removed, addedCount) { 456 function EnqueueSpliceRecord(array, index, removed, addedCount) {
445 var objectInfo = objectInfoMap.get(array); 457 var objectInfo = ObjectInfoGet(array);
446 if (!ObjectInfoHasActiveObservers(objectInfo)) 458 if (!ObjectInfoHasActiveObservers(objectInfo))
447 return; 459 return;
448 460
449 var changeRecord = { 461 var changeRecord = {
450 type: 'splice', 462 type: 'splice',
451 object: array, 463 object: array,
452 index: index, 464 index: index,
453 removed: removed, 465 removed: removed,
454 addedCount: addedCount 466 addedCount: addedCount
455 }; 467 };
456 468
457 ObjectFreeze(changeRecord); 469 ObjectFreeze(changeRecord);
458 ObjectFreeze(changeRecord.removed); 470 ObjectFreeze(changeRecord.removed);
459 ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord); 471 ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
460 } 472 }
461 473
462 function NotifyChange(type, object, name, oldValue) { 474 function NotifyChange(type, object, name, oldValue) {
463 var objectInfo = objectInfoMap.get(object); 475 var objectInfo = ObjectInfoGet(object);
464 if (!ObjectInfoHasActiveObservers(objectInfo)) 476 if (!ObjectInfoHasActiveObservers(objectInfo))
465 return; 477 return;
466 478
467 var changeRecord; 479 var changeRecord;
468 if (arguments.length == 2) { 480 if (arguments.length == 2) {
469 changeRecord = { type: type, object: object }; 481 changeRecord = { type: type, object: object };
470 } else if (arguments.length == 3) { 482 } else if (arguments.length == 3) {
471 changeRecord = { type: type, object: object, name: name }; 483 changeRecord = { type: type, object: object, name: name };
472 } else { 484 } else {
473 changeRecord = { 485 changeRecord = {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 if (IS_SPEC_OBJECT(changeRecord)) 534 if (IS_SPEC_OBJECT(changeRecord))
523 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType); 535 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType);
524 } 536 }
525 537
526 function ObjectGetNotifier(object) { 538 function ObjectGetNotifier(object) {
527 if (!IS_SPEC_OBJECT(object)) 539 if (!IS_SPEC_OBJECT(object))
528 throw MakeTypeError("observe_non_object", ["getNotifier"]); 540 throw MakeTypeError("observe_non_object", ["getNotifier"]);
529 541
530 if (ObjectIsFrozen(object)) return null; 542 if (ObjectIsFrozen(object)) return null;
531 543
532 var objectInfo = ObjectInfoGet(object); 544 var objectInfo = ObjectInfoGetOrCreate(object);
533 return ObjectInfoGetNotifier(objectInfo); 545 return ObjectInfoGetNotifier(objectInfo);
534 } 546 }
535 547
536 function CallbackDeliverPending(callback) { 548 function CallbackDeliverPending(callback) {
537 var callbackInfo = callbackInfoMap.get(callback); 549 var callbackInfo = callbackInfoMap.get(callback);
538 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo)) 550 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
539 return false; 551 return false;
540 552
541 // Clear the pending change records from callback and return it to its 553 // Clear the pending change records from callback and return it to its
542 // "optimized" state. 554 // "optimized" state.
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 "observe", ArrayObserve, 597 "observe", ArrayObserve,
586 "unobserve", ArrayUnobserve 598 "unobserve", ArrayUnobserve
587 )); 599 ));
588 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( 600 InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
589 "notify", ObjectNotifierNotify, 601 "notify", ObjectNotifierNotify,
590 "performChange", ObjectNotifierPerformChange 602 "performChange", ObjectNotifierPerformChange
591 )); 603 ));
592 } 604 }
593 605
594 SetupObjectObserve(); 606 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