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

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

Issue 663253006: Various cleanup/simplification in object-observe.js (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 1 month 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 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 "use strict"; 5 "use strict";
6 6
7 // Overview: 7 // Overview:
8 // 8 //
9 // This file contains all of the routing and accounting for Object.observe. 9 // This file contains all of the routing and accounting for Object.observe.
10 // User code will interact with these mechanisms via the Object.observe APIs 10 // User code will interact with these mechanisms via the Object.observe APIs
(...skipping 17 matching lines...) Expand all
28 // (i.e. not Object.deliverChangeRecords), this is the mechanism by which 28 // (i.e. not Object.deliverChangeRecords), this is the mechanism by which
29 // callbacks are invoked in the proper order until there are no more 29 // callbacks are invoked in the proper order until there are no more
30 // change records pending to a callback. 30 // change records pending to a callback.
31 // 31 //
32 // Note that in order to reduce allocation and processing costs, the 32 // Note that in order to reduce allocation and processing costs, the
33 // implementation of (1) and (2) have "optimized" states which represent 33 // implementation of (1) and (2) have "optimized" states which represent
34 // common cases which can be handled more efficiently. 34 // common cases which can be handled more efficiently.
35 35
36 var observationState; 36 var observationState;
37 37
38 // We have to wait until after bootstrapping to grab a reference to the
39 // observationState object, since it's not possible to serialize that
40 // reference into the snapshot.
38 function GetObservationStateJS() { 41 function GetObservationStateJS() {
39 if (IS_UNDEFINED(observationState)) 42 if (IS_UNDEFINED(observationState)) {
40 observationState = %GetObservationState(); 43 observationState = %GetObservationState();
44 }
41 45
46 // TODO(adamk): Consider moving this code into heap.cc
42 if (IS_UNDEFINED(observationState.callbackInfoMap)) { 47 if (IS_UNDEFINED(observationState.callbackInfoMap)) {
43 observationState.callbackInfoMap = %ObservationWeakMapCreate(); 48 observationState.callbackInfoMap = %ObservationWeakMapCreate();
44 observationState.objectInfoMap = %ObservationWeakMapCreate(); 49 observationState.objectInfoMap = %ObservationWeakMapCreate();
45 observationState.notifierObjectInfoMap = %ObservationWeakMapCreate(); 50 observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
46 observationState.pendingObservers = null; 51 observationState.pendingObservers = null;
47 observationState.nextCallbackPriority = 0; 52 observationState.nextCallbackPriority = 0;
48 observationState.lastMicrotaskId = 0; 53 observationState.lastMicrotaskId = 0;
49 } 54 }
50 55
51 return observationState; 56 return observationState;
52 } 57 }
53 58
54 function GetWeakMapWrapper() {
55 function MapWrapper(map) {
56 this.map_ = map;
57 };
58
59 MapWrapper.prototype = {
60 __proto__: null,
61 get: function(key) {
62 return %WeakCollectionGet(this.map_, key);
63 },
64 set: function(key, value) {
65 %WeakCollectionSet(this.map_, key, value);
66 },
67 has: function(key) {
68 return !IS_UNDEFINED(this.get(key));
69 }
70 };
71
72 return MapWrapper;
73 }
74
75 var contextMaps;
76
77 function GetContextMaps() {
78 if (IS_UNDEFINED(contextMaps)) {
79 var map = GetWeakMapWrapper();
80 var observationState = GetObservationStateJS();
81 contextMaps = {
82 callbackInfoMap: new map(observationState.callbackInfoMap),
83 objectInfoMap: new map(observationState.objectInfoMap),
84 notifierObjectInfoMap: new map(observationState.notifierObjectInfoMap)
85 };
86 }
87
88 return contextMaps;
89 }
90
91 function GetCallbackInfoMap() {
92 return GetContextMaps().callbackInfoMap;
93 }
94
95 function GetObjectInfoMap() {
96 return GetContextMaps().objectInfoMap;
97 }
98
99 function GetNotifierObjectInfoMap() {
100 return GetContextMaps().notifierObjectInfoMap;
101 }
102
103 function GetPendingObservers() { 59 function GetPendingObservers() {
104 return GetObservationStateJS().pendingObservers; 60 return GetObservationStateJS().pendingObservers;
105 } 61 }
106 62
107 function SetPendingObservers(pendingObservers) { 63 function SetPendingObservers(pendingObservers) {
108 GetObservationStateJS().pendingObservers = pendingObservers; 64 GetObservationStateJS().pendingObservers = pendingObservers;
109 } 65 }
110 66
111 function GetNextCallbackPriority() { 67 function GetNextCallbackPriority() {
112 return GetObservationStateJS().nextCallbackPriority++; 68 return GetObservationStateJS().nextCallbackPriority++;
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
197 if (!%_IsJSProxy(object)) { 153 if (!%_IsJSProxy(object)) {
198 %SetIsObserved(object); 154 %SetIsObserved(object);
199 } 155 }
200 objectInfo = { 156 objectInfo = {
201 object: object, 157 object: object,
202 changeObservers: null, 158 changeObservers: null,
203 notifier: null, 159 notifier: null,
204 performing: null, 160 performing: null,
205 performingCount: 0, 161 performingCount: 0,
206 }; 162 };
207 GetObjectInfoMap().set(object, objectInfo); 163 %WeakCollectionSet(GetObservationStateJS().objectInfoMap,
164 object, objectInfo);
208 } 165 }
209 return objectInfo; 166 return objectInfo;
210 } 167 }
211 168
212 function ObjectInfoGet(object) { 169 function ObjectInfoGet(object) {
213 return GetObjectInfoMap().get(object); 170 return %WeakCollectionGet(GetObservationStateJS().objectInfoMap, object);
214 } 171 }
215 172
216 function ObjectInfoGetFromNotifier(notifier) { 173 function ObjectInfoGetFromNotifier(notifier) {
217 return GetNotifierObjectInfoMap().get(notifier); 174 return %WeakCollectionGet(GetObservationStateJS().notifierObjectInfoMap,
175 notifier);
218 } 176 }
219 177
220 function ObjectInfoGetNotifier(objectInfo) { 178 function ObjectInfoGetNotifier(objectInfo) {
221 if (IS_NULL(objectInfo.notifier)) { 179 if (IS_NULL(objectInfo.notifier)) {
222 objectInfo.notifier = { __proto__: notifierPrototype }; 180 objectInfo.notifier = { __proto__: notifierPrototype };
223 GetNotifierObjectInfoMap().set(objectInfo.notifier, objectInfo); 181 %WeakCollectionSet(GetObservationStateJS().notifierObjectInfoMap,
182 objectInfo.notifier, objectInfo);
224 } 183 }
225 184
226 return objectInfo.notifier; 185 return objectInfo.notifier;
227 } 186 }
228 187
229 function ObjectInfoGetObject(objectInfo) {
230 return objectInfo.object;
231 }
232
233 function ChangeObserversIsOptimized(changeObservers) { 188 function ChangeObserversIsOptimized(changeObservers) {
234 return typeof changeObservers === 'function' || 189 return IS_SPEC_FUNCTION(changeObservers) ||
235 typeof changeObservers.callback === 'function'; 190 IS_SPEC_FUNCTION(changeObservers.callback);
236 } 191 }
237 192
238 // The set of observers on an object is called 'changeObservers'. The first 193 // The set of observers on an object is called 'changeObservers'. The first
239 // observer is referenced directly via objectInfo.changeObservers. When a second 194 // observer is referenced directly via objectInfo.changeObservers. When a second
240 // is added, changeObservers "normalizes" to become a mapping of callback 195 // is added, changeObservers "normalizes" to become a mapping of callback
241 // priority -> observer and is then stored on objectInfo.changeObservers. 196 // priority -> observer and is then stored on objectInfo.changeObservers.
242 function ObjectInfoNormalizeChangeObservers(objectInfo) { 197 function ObjectInfoNormalizeChangeObservers(objectInfo) {
243 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { 198 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
244 var observer = objectInfo.changeObservers; 199 var observer = objectInfo.changeObservers;
245 var callback = ObserverGetCallback(observer); 200 var callback = ObserverGetCallback(observer);
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
321 var len = ToInteger(arg.length); 276 var len = ToInteger(arg.length);
322 if (len < 0) len = 0; 277 if (len < 0) len = 0;
323 278
324 return TypeMapCreateFromList(arg, len); 279 return TypeMapCreateFromList(arg, len);
325 } 280 }
326 281
327 // CallbackInfo's optimized state is just a number which represents its global 282 // CallbackInfo's optimized state is just a number which represents its global
328 // priority. When a change record must be enqueued for the callback, it 283 // priority. When a change record must be enqueued for the callback, it
329 // normalizes. When delivery clears any pending change records, it re-optimizes. 284 // normalizes. When delivery clears any pending change records, it re-optimizes.
330 function CallbackInfoGet(callback) { 285 function CallbackInfoGet(callback) {
331 return GetCallbackInfoMap().get(callback); 286 return %WeakCollectionGet(GetObservationStateJS().callbackInfoMap, callback);
287 }
288
289 function CallbackInfoSet(callback, callbackInfo) {
290 %WeakCollectionSet(GetObservationStateJS().callbackInfoMap,
291 callback, callbackInfo);
332 } 292 }
333 293
334 function CallbackInfoGetOrCreate(callback) { 294 function CallbackInfoGetOrCreate(callback) {
335 var callbackInfo = GetCallbackInfoMap().get(callback); 295 var callbackInfo = CallbackInfoGet(callback);
336 if (!IS_UNDEFINED(callbackInfo)) 296 if (!IS_UNDEFINED(callbackInfo))
337 return callbackInfo; 297 return callbackInfo;
338 298
339 var priority = GetNextCallbackPriority(); 299 var priority = GetNextCallbackPriority();
340 GetCallbackInfoMap().set(callback, priority); 300 CallbackInfoSet(callback, priority);
341 return priority; 301 return priority;
342 } 302 }
343 303
344 function CallbackInfoGetPriority(callbackInfo) { 304 function CallbackInfoGetPriority(callbackInfo) {
345 if (IS_NUMBER(callbackInfo)) 305 if (IS_NUMBER(callbackInfo))
346 return callbackInfo; 306 return callbackInfo;
347 else 307 else
348 return callbackInfo.priority; 308 return callbackInfo.priority;
349 } 309 }
350 310
351 function CallbackInfoNormalize(callback) { 311 function CallbackInfoNormalize(callback) {
352 var callbackInfo = GetCallbackInfoMap().get(callback); 312 var callbackInfo = CallbackInfoGet(callback);
353 if (IS_NUMBER(callbackInfo)) { 313 if (IS_NUMBER(callbackInfo)) {
354 var priority = callbackInfo; 314 var priority = callbackInfo;
355 callbackInfo = new InternalArray; 315 callbackInfo = new InternalArray;
356 callbackInfo.priority = priority; 316 callbackInfo.priority = priority;
357 GetCallbackInfoMap().set(callback, callbackInfo); 317 CallbackInfoSet(callback, callbackInfo);
358 } 318 }
359 return callbackInfo; 319 return callbackInfo;
360 } 320 }
361 321
362 function ObjectObserve(object, callback, acceptList) { 322 function ObjectObserve(object, callback, acceptList) {
363 if (!IS_SPEC_OBJECT(object)) 323 if (!IS_SPEC_OBJECT(object))
364 throw MakeTypeError("observe_non_object", ["observe"]); 324 throw MakeTypeError("observe_non_object", ["observe"]);
365 if (%IsJSGlobalProxy(object)) 325 if (%IsJSGlobalProxy(object))
366 throw MakeTypeError("observe_global_proxy", ["observe"]); 326 throw MakeTypeError("observe_global_proxy", ["observe"]);
367 if (!IS_SPEC_FUNCTION(callback)) 327 if (!IS_SPEC_FUNCTION(callback))
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
438 GetPendingObservers()[callbackInfo.priority] = callback; 398 GetPendingObservers()[callbackInfo.priority] = callback;
439 callbackInfo.push(changeRecord); 399 callbackInfo.push(changeRecord);
440 } 400 }
441 401
442 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) { 402 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) {
443 if (!ObjectInfoHasActiveObservers(objectInfo)) 403 if (!ObjectInfoHasActiveObservers(objectInfo))
444 return; 404 return;
445 405
446 var hasType = !IS_UNDEFINED(type); 406 var hasType = !IS_UNDEFINED(type);
447 var newRecord = hasType ? 407 var newRecord = hasType ?
448 { object: ObjectInfoGetObject(objectInfo), type: type } : 408 { object: objectInfo.object, type: type } :
449 { object: ObjectInfoGetObject(objectInfo) }; 409 { object: objectInfo.object };
450 410
451 for (var prop in changeRecord) { 411 for (var prop in changeRecord) {
452 if (prop === 'object' || (hasType && prop === 'type')) continue; 412 if (prop === 'object' || (hasType && prop === 'type')) continue;
453 %DefineDataPropertyUnchecked( 413 %DefineDataPropertyUnchecked(
454 newRecord, prop, changeRecord[prop], READ_ONLY + DONT_DELETE); 414 newRecord, prop, changeRecord[prop], READ_ONLY + DONT_DELETE);
455 } 415 }
456 ObjectFreezeJS(newRecord); 416 ObjectFreezeJS(newRecord);
457 417
458 ObjectInfoEnqueueInternalChangeRecord(objectInfo, newRecord); 418 ObjectInfoEnqueueInternalChangeRecord(objectInfo, newRecord);
459 } 419 }
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
587 var getNotifierFn = %GetObjectContextObjectGetNotifier(object); 547 var getNotifierFn = %GetObjectContextObjectGetNotifier(object);
588 return getNotifierFn(object); 548 return getNotifierFn(object);
589 } 549 }
590 550
591 function NativeObjectGetNotifier(object) { 551 function NativeObjectGetNotifier(object) {
592 var objectInfo = ObjectInfoGetOrCreate(object); 552 var objectInfo = ObjectInfoGetOrCreate(object);
593 return ObjectInfoGetNotifier(objectInfo); 553 return ObjectInfoGetNotifier(objectInfo);
594 } 554 }
595 555
596 function CallbackDeliverPending(callback) { 556 function CallbackDeliverPending(callback) {
597 var callbackInfo = GetCallbackInfoMap().get(callback); 557 var callbackInfo = CallbackInfoGet(callback);
598 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo)) 558 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
599 return false; 559 return false;
600 560
601 // Clear the pending change records from callback and return it to its 561 // Clear the pending change records from callback and return it to its
602 // "optimized" state. 562 // "optimized" state.
603 var priority = callbackInfo.priority; 563 var priority = callbackInfo.priority;
604 GetCallbackInfoMap().set(callback, priority); 564 CallbackInfoSet(callback, priority);
605 565
606 if (GetPendingObservers()) 566 var pendingObservers = GetPendingObservers();
607 delete GetPendingObservers()[priority]; 567 if (!IS_NULL(pendingObservers))
568 delete pendingObservers[priority];
608 569
609 var delivered = []; 570 var delivered = [];
610 %MoveArrayContents(callbackInfo, delivered); 571 %MoveArrayContents(callbackInfo, delivered);
611 572
612 try { 573 try {
613 %_CallFunction(UNDEFINED, delivered, callback); 574 %_CallFunction(UNDEFINED, delivered, callback);
614 } catch (ex) {} // TODO(rossberg): perhaps log uncaught exceptions. 575 } catch (ex) {} // TODO(rossberg): perhaps log uncaught exceptions.
615 return true; 576 return true;
616 } 577 }
617 578
618 function ObjectDeliverChangeRecords(callback) { 579 function ObjectDeliverChangeRecords(callback) {
619 if (!IS_SPEC_FUNCTION(callback)) 580 if (!IS_SPEC_FUNCTION(callback))
620 throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]); 581 throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]);
621 582
622 while (CallbackDeliverPending(callback)) {} 583 while (CallbackDeliverPending(callback)) {}
623 } 584 }
624 585
625 function ObserveMicrotaskRunner() { 586 function ObserveMicrotaskRunner() {
626 var pendingObservers = GetPendingObservers(); 587 var pendingObservers = GetPendingObservers();
627 if (pendingObservers) { 588 if (!IS_NULL(pendingObservers)) {
628 SetPendingObservers(null); 589 SetPendingObservers(null);
629 for (var i in pendingObservers) { 590 for (var i in pendingObservers) {
630 CallbackDeliverPending(pendingObservers[i]); 591 CallbackDeliverPending(pendingObservers[i]);
631 } 592 }
632 } 593 }
633 } 594 }
634 595
635 function SetupObjectObserve() { 596 function SetupObjectObserve() {
636 %CheckIsBootstrapping(); 597 %CheckIsBootstrapping();
637 InstallFunctions($Object, DONT_ENUM, $Array( 598 InstallFunctions($Object, DONT_ENUM, $Array(
638 "deliverChangeRecords", ObjectDeliverChangeRecords, 599 "deliverChangeRecords", ObjectDeliverChangeRecords,
639 "getNotifier", ObjectGetNotifier, 600 "getNotifier", ObjectGetNotifier,
640 "observe", ObjectObserve, 601 "observe", ObjectObserve,
641 "unobserve", ObjectUnobserve 602 "unobserve", ObjectUnobserve
642 )); 603 ));
643 InstallFunctions($Array, DONT_ENUM, $Array( 604 InstallFunctions($Array, DONT_ENUM, $Array(
644 "observe", ArrayObserve, 605 "observe", ArrayObserve,
645 "unobserve", ArrayUnobserve 606 "unobserve", ArrayUnobserve
646 )); 607 ));
647 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( 608 InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
648 "notify", ObjectNotifierNotify, 609 "notify", ObjectNotifierNotify,
649 "performChange", ObjectNotifierPerformChange 610 "performChange", ObjectNotifierPerformChange
650 )); 611 ));
651 } 612 }
652 613
653 SetupObjectObserve(); 614 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