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

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

Issue 198383002: Reland "Enable Object.observe by default" again (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 9 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 | « src/ic.cc ('k') | src/objects.cc » ('j') | 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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 // 3) observationState.pendingObservers. This is the set of observers which 49 // 3) observationState.pendingObservers. This is the set of observers which
50 // have change records which must be delivered. During "normal" delivery 50 // have change records which must be delivered. During "normal" delivery
51 // (i.e. not Object.deliverChangeRecords), this is the mechanism by which 51 // (i.e. not Object.deliverChangeRecords), this is the mechanism by which
52 // callbacks are invoked in the proper order until there are no more 52 // callbacks are invoked in the proper order until there are no more
53 // change records pending to a callback. 53 // change records pending to a callback.
54 // 54 //
55 // Note that in order to reduce allocation and processing costs, the 55 // Note that in order to reduce allocation and processing costs, the
56 // implementation of (1) and (2) have "optimized" states which represent 56 // implementation of (1) and (2) have "optimized" states which represent
57 // common cases which can be handled more efficiently. 57 // common cases which can be handled more efficiently.
58 58
59 var observationState = %GetObservationState(); 59 var observationState;
60 if (IS_UNDEFINED(observationState.callbackInfoMap)) { 60
61 observationState.callbackInfoMap = %ObservationWeakMapCreate(); 61 function GetObservationState() {
62 observationState.objectInfoMap = %ObservationWeakMapCreate(); 62 if (IS_UNDEFINED(observationState))
63 observationState.notifierObjectInfoMap = %ObservationWeakMapCreate(); 63 observationState = %GetObservationState();
64 observationState.pendingObservers = null; 64
65 observationState.nextCallbackPriority = 0; 65 if (IS_UNDEFINED(observationState.callbackInfoMap)) {
66 observationState.callbackInfoMap = %ObservationWeakMapCreate();
67 observationState.objectInfoMap = %ObservationWeakMapCreate();
68 observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
69 observationState.pendingObservers = null;
70 observationState.nextCallbackPriority = 0;
71 }
72
73 return observationState;
66 } 74 }
67 75
68 function ObservationWeakMap(map) { 76 function GetWeakMapWrapper() {
69 this.map_ = map; 77 function MapWrapper(map) {
78 this.map_ = map;
79 };
80
81 MapWrapper.prototype = {
82 get: function(key) {
83 key = %UnwrapGlobalProxy(key);
84 if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
85 return %WeakCollectionGet(this.map_, key);
86 },
87 set: function(key, value) {
88 key = %UnwrapGlobalProxy(key);
89 if (!IS_SPEC_OBJECT(key)) return UNDEFINED;
90 %WeakCollectionSet(this.map_, key, value);
91 },
92 has: function(key) {
93 return !IS_UNDEFINED(this.get(key));
94 }
95 };
96
97 return MapWrapper;
70 } 98 }
71 99
72 ObservationWeakMap.prototype = { 100 var contextMaps;
73 get: function(key) { 101
74 key = %UnwrapGlobalProxy(key); 102 function GetContextMaps() {
75 if (!IS_SPEC_OBJECT(key)) return UNDEFINED; 103 if (IS_UNDEFINED(contextMaps)) {
76 return %WeakCollectionGet(this.map_, key); 104 var map = GetWeakMapWrapper();
77 }, 105 var observationState = GetObservationState();
78 set: function(key, value) { 106 contextMaps = {
79 key = %UnwrapGlobalProxy(key); 107 callbackInfoMap: new map(observationState.callbackInfoMap),
80 if (!IS_SPEC_OBJECT(key)) return UNDEFINED; 108 objectInfoMap: new map(observationState.objectInfoMap),
81 %WeakCollectionSet(this.map_, key, value); 109 notifierObjectInfoMap: new map(observationState.notifierObjectInfoMap)
82 }, 110 };
83 has: function(key) {
84 return !IS_UNDEFINED(this.get(key));
85 } 111 }
86 };
87 112
88 var callbackInfoMap = 113 return contextMaps;
89 new ObservationWeakMap(observationState.callbackInfoMap); 114 }
90 var objectInfoMap = new ObservationWeakMap(observationState.objectInfoMap); 115
91 var notifierObjectInfoMap = 116 function GetCallbackInfoMap() {
92 new ObservationWeakMap(observationState.notifierObjectInfoMap); 117 return GetContextMaps().callbackInfoMap;
118 }
119
120 function GetObjectInfoMap() {
121 return GetContextMaps().objectInfoMap;
122 }
123
124 function GetNotifierObjectInfoMap() {
125 return GetContextMaps().notifierObjectInfoMap;
126 }
127
128 function GetPendingObservers() {
129 return GetObservationState().pendingObservers;
130 }
131
132 function SetPendingObservers(pendingObservers) {
133 GetObservationState().pendingObservers = pendingObservers;
134 }
135
136 function GetNextCallbackPriority() {
137 return GetObservationState().nextCallbackPriority++;
138 }
93 139
94 function nullProtoObject() { 140 function nullProtoObject() {
95 return { __proto__: null }; 141 return { __proto__: null };
96 } 142 }
97 143
98 function TypeMapCreate() { 144 function TypeMapCreate() {
99 return nullProtoObject(); 145 return nullProtoObject();
100 } 146 }
101 147
102 function TypeMapAddType(typeMap, type, ignoreDuplicate) { 148 function TypeMapAddType(typeMap, type, ignoreDuplicate) {
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
173 if (!%IsJSProxy(object)) 219 if (!%IsJSProxy(object))
174 %SetIsObserved(object); 220 %SetIsObserved(object);
175 221
176 objectInfo = { 222 objectInfo = {
177 object: object, 223 object: object,
178 changeObservers: null, 224 changeObservers: null,
179 notifier: null, 225 notifier: null,
180 performing: null, 226 performing: null,
181 performingCount: 0, 227 performingCount: 0,
182 }; 228 };
183 objectInfoMap.set(object, objectInfo); 229 GetObjectInfoMap().set(object, objectInfo);
184 } 230 }
185 return objectInfo; 231 return objectInfo;
186 } 232 }
187 233
188 function ObjectInfoGet(object) { 234 function ObjectInfoGet(object) {
189 return objectInfoMap.get(object); 235 return GetObjectInfoMap().get(object);
190 } 236 }
191 237
192 function ObjectInfoGetFromNotifier(notifier) { 238 function ObjectInfoGetFromNotifier(notifier) {
193 return notifierObjectInfoMap.get(notifier); 239 return GetNotifierObjectInfoMap().get(notifier);
194 } 240 }
195 241
196 function ObjectInfoGetNotifier(objectInfo) { 242 function ObjectInfoGetNotifier(objectInfo) {
197 if (IS_NULL(objectInfo.notifier)) { 243 if (IS_NULL(objectInfo.notifier)) {
198 objectInfo.notifier = { __proto__: notifierPrototype }; 244 objectInfo.notifier = { __proto__: notifierPrototype };
199 notifierObjectInfoMap.set(objectInfo.notifier, objectInfo); 245 GetNotifierObjectInfoMap().set(objectInfo.notifier, objectInfo);
200 } 246 }
201 247
202 return objectInfo.notifier; 248 return objectInfo.notifier;
203 } 249 }
204 250
205 function ObjectInfoGetObject(objectInfo) { 251 function ObjectInfoGetObject(objectInfo) {
206 return objectInfo.object; 252 return objectInfo.object;
207 } 253 }
208 254
209 function ChangeObserversIsOptimized(changeObservers) { 255 function ChangeObserversIsOptimized(changeObservers) {
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 arg.length < 0) 341 arg.length < 0)
296 return false; 342 return false;
297 343
298 return true; 344 return true;
299 } 345 }
300 346
301 // CallbackInfo's optimized state is just a number which represents its global 347 // CallbackInfo's optimized state is just a number which represents its global
302 // priority. When a change record must be enqueued for the callback, it 348 // priority. When a change record must be enqueued for the callback, it
303 // normalizes. When delivery clears any pending change records, it re-optimizes. 349 // normalizes. When delivery clears any pending change records, it re-optimizes.
304 function CallbackInfoGet(callback) { 350 function CallbackInfoGet(callback) {
305 return callbackInfoMap.get(callback); 351 return GetCallbackInfoMap().get(callback);
306 } 352 }
307 353
308 function CallbackInfoGetOrCreate(callback) { 354 function CallbackInfoGetOrCreate(callback) {
309 var callbackInfo = callbackInfoMap.get(callback); 355 var callbackInfo = GetCallbackInfoMap().get(callback);
310 if (!IS_UNDEFINED(callbackInfo)) 356 if (!IS_UNDEFINED(callbackInfo))
311 return callbackInfo; 357 return callbackInfo;
312 358
313 var priority = observationState.nextCallbackPriority++ 359 var priority = GetNextCallbackPriority();
314 callbackInfoMap.set(callback, priority); 360 GetCallbackInfoMap().set(callback, priority);
315 return priority; 361 return priority;
316 } 362 }
317 363
318 function CallbackInfoGetPriority(callbackInfo) { 364 function CallbackInfoGetPriority(callbackInfo) {
319 if (IS_NUMBER(callbackInfo)) 365 if (IS_NUMBER(callbackInfo))
320 return callbackInfo; 366 return callbackInfo;
321 else 367 else
322 return callbackInfo.priority; 368 return callbackInfo.priority;
323 } 369 }
324 370
325 function CallbackInfoNormalize(callback) { 371 function CallbackInfoNormalize(callback) {
326 var callbackInfo = callbackInfoMap.get(callback); 372 var callbackInfo = GetCallbackInfoMap().get(callback);
327 if (IS_NUMBER(callbackInfo)) { 373 if (IS_NUMBER(callbackInfo)) {
328 var priority = callbackInfo; 374 var priority = callbackInfo;
329 callbackInfo = new InternalArray; 375 callbackInfo = new InternalArray;
330 callbackInfo.priority = priority; 376 callbackInfo.priority = priority;
331 callbackInfoMap.set(callback, callbackInfo); 377 GetCallbackInfoMap().set(callback, callbackInfo);
332 } 378 }
333 return callbackInfo; 379 return callbackInfo;
334 } 380 }
335 381
336 function ObjectObserve(object, callback, acceptList) { 382 function ObjectObserve(object, callback, acceptList) {
337 if (!IS_SPEC_OBJECT(object)) 383 if (!IS_SPEC_OBJECT(object))
338 throw MakeTypeError("observe_non_object", ["observe"]); 384 throw MakeTypeError("observe_non_object", ["observe"]);
339 if (!IS_SPEC_FUNCTION(callback)) 385 if (!IS_SPEC_FUNCTION(callback))
340 throw MakeTypeError("observe_non_function", ["observe"]); 386 throw MakeTypeError("observe_non_function", ["observe"]);
341 if (ObjectIsFrozen(callback)) 387 if (ObjectIsFrozen(callback))
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 var callback = ObserverGetCallback(observer); 429 var callback = ObserverGetCallback(observer);
384 if (needsAccessCheck && 430 if (needsAccessCheck &&
385 // Drop all splice records on the floor for access-checked objects 431 // Drop all splice records on the floor for access-checked objects
386 (changeRecord.type == 'splice' || 432 (changeRecord.type == 'splice' ||
387 !%IsAccessAllowedForObserver( 433 !%IsAccessAllowedForObserver(
388 callback, changeRecord.object, changeRecord.name))) { 434 callback, changeRecord.object, changeRecord.name))) {
389 return; 435 return;
390 } 436 }
391 437
392 var callbackInfo = CallbackInfoNormalize(callback); 438 var callbackInfo = CallbackInfoNormalize(callback);
393 if (IS_NULL(observationState.pendingObservers)) { 439 if (IS_NULL(GetPendingObservers())) {
394 observationState.pendingObservers = nullProtoObject(); 440 SetPendingObservers(nullProtoObject())
395 GetMicrotaskQueue().push(ObserveMicrotaskRunner); 441 GetMicrotaskQueue().push(ObserveMicrotaskRunner);
396 %SetMicrotaskPending(true); 442 %SetMicrotaskPending(true);
397 } 443 }
398 observationState.pendingObservers[callbackInfo.priority] = callback; 444 GetPendingObservers()[callbackInfo.priority] = callback;
399 callbackInfo.push(changeRecord); 445 callbackInfo.push(changeRecord);
400 } 446 }
401 447
402 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) { 448 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) {
403 if (!ObjectInfoHasActiveObservers(objectInfo)) 449 if (!ObjectInfoHasActiveObservers(objectInfo))
404 return; 450 return;
405 451
406 var hasType = !IS_UNDEFINED(type); 452 var hasType = !IS_UNDEFINED(type);
407 var newRecord = hasType ? 453 var newRecord = hasType ?
408 { object: ObjectInfoGetObject(objectInfo), type: type } : 454 { object: ObjectInfoGetObject(objectInfo), type: type } :
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after
541 if (!IS_SPEC_OBJECT(object)) 587 if (!IS_SPEC_OBJECT(object))
542 throw MakeTypeError("observe_non_object", ["getNotifier"]); 588 throw MakeTypeError("observe_non_object", ["getNotifier"]);
543 589
544 if (ObjectIsFrozen(object)) return null; 590 if (ObjectIsFrozen(object)) return null;
545 591
546 var objectInfo = ObjectInfoGetOrCreate(object); 592 var objectInfo = ObjectInfoGetOrCreate(object);
547 return ObjectInfoGetNotifier(objectInfo); 593 return ObjectInfoGetNotifier(objectInfo);
548 } 594 }
549 595
550 function CallbackDeliverPending(callback) { 596 function CallbackDeliverPending(callback) {
551 var callbackInfo = callbackInfoMap.get(callback); 597 var callbackInfo = GetCallbackInfoMap().get(callback);
552 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo)) 598 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
553 return false; 599 return false;
554 600
555 // Clear the pending change records from callback and return it to its 601 // Clear the pending change records from callback and return it to its
556 // "optimized" state. 602 // "optimized" state.
557 var priority = callbackInfo.priority; 603 var priority = callbackInfo.priority;
558 callbackInfoMap.set(callback, priority); 604 GetCallbackInfoMap().set(callback, priority);
559 605
560 if (observationState.pendingObservers) 606 if (GetPendingObservers())
561 delete observationState.pendingObservers[priority]; 607 delete GetPendingObservers()[priority];
562 608
563 var delivered = []; 609 var delivered = [];
564 %MoveArrayContents(callbackInfo, delivered); 610 %MoveArrayContents(callbackInfo, delivered);
565 611
566 try { 612 try {
567 %_CallFunction(UNDEFINED, delivered, callback); 613 %_CallFunction(UNDEFINED, delivered, callback);
568 } catch (ex) {} // TODO(rossberg): perhaps log uncaught exceptions. 614 } catch (ex) {} // TODO(rossberg): perhaps log uncaught exceptions.
569 return true; 615 return true;
570 } 616 }
571 617
572 function ObjectDeliverChangeRecords(callback) { 618 function ObjectDeliverChangeRecords(callback) {
573 if (!IS_SPEC_FUNCTION(callback)) 619 if (!IS_SPEC_FUNCTION(callback))
574 throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]); 620 throw MakeTypeError("observe_non_function", ["deliverChangeRecords"]);
575 621
576 while (CallbackDeliverPending(callback)) {} 622 while (CallbackDeliverPending(callback)) {}
577 } 623 }
578 624
579 function ObserveMicrotaskRunner() { 625 function ObserveMicrotaskRunner() {
580 var pendingObservers = observationState.pendingObservers; 626 var pendingObservers = GetPendingObservers();
581 if (pendingObservers) { 627 if (pendingObservers) {
582 observationState.pendingObservers = null; 628 SetPendingObservers(null);
583 for (var i in pendingObservers) { 629 for (var i in pendingObservers) {
584 CallbackDeliverPending(pendingObservers[i]); 630 CallbackDeliverPending(pendingObservers[i]);
585 } 631 }
586 } 632 }
587 } 633 }
588 634
589 function SetupObjectObserve() { 635 function SetupObjectObserve() {
590 %CheckIsBootstrapping(); 636 %CheckIsBootstrapping();
591 InstallFunctions($Object, DONT_ENUM, $Array( 637 InstallFunctions($Object, DONT_ENUM, $Array(
592 "deliverChangeRecords", ObjectDeliverChangeRecords, 638 "deliverChangeRecords", ObjectDeliverChangeRecords,
593 "getNotifier", ObjectGetNotifier, 639 "getNotifier", ObjectGetNotifier,
594 "observe", ObjectObserve, 640 "observe", ObjectObserve,
595 "unobserve", ObjectUnobserve 641 "unobserve", ObjectUnobserve
596 )); 642 ));
597 InstallFunctions($Array, DONT_ENUM, $Array( 643 InstallFunctions($Array, DONT_ENUM, $Array(
598 "observe", ArrayObserve, 644 "observe", ArrayObserve,
599 "unobserve", ArrayUnobserve 645 "unobserve", ArrayUnobserve
600 )); 646 ));
601 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( 647 InstallFunctions(notifierPrototype, DONT_ENUM, $Array(
602 "notify", ObjectNotifierNotify, 648 "notify", ObjectNotifierNotify,
603 "performChange", ObjectNotifierPerformChange 649 "performChange", ObjectNotifierPerformChange
604 )); 650 ));
605 } 651 }
606 652
607 SetupObjectObserve(); 653 SetupObjectObserve();
OLDNEW
« no previous file with comments | « src/ic.cc ('k') | src/objects.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698