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 1398733002: Move builtin JavaScript sources into own directory. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Also move macros.py file. Created 5 years, 2 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 | « src/messages.js ('k') | src/prologue.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 var $observeEnqueueSpliceRecord;
6 var $observeBeginPerformSplice;
7 var $observeEndPerformSplice;
8
9 var $observeObjectMethods;
10 var $observeArrayMethods;
11
12 (function(global, utils) {
13
14 "use strict";
15
16 %CheckIsBootstrapping();
17
18 // -------------------------------------------------------------------
19 // Imports
20
21 var GlobalArray = global.Array;
22 var GlobalObject = global.Object;
23 var InternalArray = utils.InternalArray;
24
25 var ObjectFreeze;
26 var ObjectIsFrozen;
27
28 utils.Import(function(from) {
29 ObjectFreeze = from.ObjectFreeze;
30 ObjectIsFrozen = from.ObjectIsFrozen;
31 });
32
33 // -------------------------------------------------------------------
34
35 // Overview:
36 //
37 // This file contains all of the routing and accounting for Object.observe.
38 // User code will interact with these mechanisms via the Object.observe APIs
39 // and, as a side effect of mutation objects which are observed. The V8 runtime
40 // (both C++ and JS) will interact with these mechanisms primarily by enqueuing
41 // proper change records for objects which were mutated. The Object.observe
42 // routing and accounting consists primarily of three participants
43 //
44 // 1) ObjectInfo. This represents the observed state of a given object. It
45 // records what callbacks are observing the object, with what options, and
46 // what "change types" are in progress on the object (i.e. via
47 // notifier.performChange).
48 //
49 // 2) CallbackInfo. This represents a callback used for observation. It holds
50 // the records which must be delivered to the callback, as well as the global
51 // priority of the callback (which determines delivery order between
52 // callbacks).
53 //
54 // 3) observationState.pendingObservers. This is the set of observers which
55 // have change records which must be delivered. During "normal" delivery
56 // (i.e. not Object.deliverChangeRecords), this is the mechanism by which
57 // callbacks are invoked in the proper order until there are no more
58 // change records pending to a callback.
59 //
60 // Note that in order to reduce allocation and processing costs, the
61 // implementation of (1) and (2) have "optimized" states which represent
62 // common cases which can be handled more efficiently.
63
64 var observationState;
65
66 var notifierPrototype = {};
67
68 // We have to wait until after bootstrapping to grab a reference to the
69 // observationState object, since it's not possible to serialize that
70 // reference into the snapshot.
71 function GetObservationStateJS() {
72 if (IS_UNDEFINED(observationState)) {
73 observationState = %GetObservationState();
74 }
75
76 // TODO(adamk): Consider moving this code into heap.cc
77 if (IS_UNDEFINED(observationState.callbackInfoMap)) {
78 observationState.callbackInfoMap = %ObservationWeakMapCreate();
79 observationState.objectInfoMap = %ObservationWeakMapCreate();
80 observationState.notifierObjectInfoMap = %ObservationWeakMapCreate();
81 observationState.pendingObservers = null;
82 observationState.nextCallbackPriority = 0;
83 observationState.lastMicrotaskId = 0;
84 }
85
86 return observationState;
87 }
88
89
90 function GetPendingObservers() {
91 return GetObservationStateJS().pendingObservers;
92 }
93
94
95 function SetPendingObservers(pendingObservers) {
96 GetObservationStateJS().pendingObservers = pendingObservers;
97 }
98
99
100 function GetNextCallbackPriority() {
101 return GetObservationStateJS().nextCallbackPriority++;
102 }
103
104
105 function nullProtoObject() {
106 return { __proto__: null };
107 }
108
109
110 function TypeMapCreate() {
111 return nullProtoObject();
112 }
113
114
115 function TypeMapAddType(typeMap, type, ignoreDuplicate) {
116 typeMap[type] = ignoreDuplicate ? 1 : (typeMap[type] || 0) + 1;
117 }
118
119
120 function TypeMapRemoveType(typeMap, type) {
121 typeMap[type]--;
122 }
123
124
125 function TypeMapCreateFromList(typeList, length) {
126 var typeMap = TypeMapCreate();
127 for (var i = 0; i < length; i++) {
128 TypeMapAddType(typeMap, typeList[i], true);
129 }
130 return typeMap;
131 }
132
133
134 function TypeMapHasType(typeMap, type) {
135 return !!typeMap[type];
136 }
137
138
139 function TypeMapIsDisjointFrom(typeMap1, typeMap2) {
140 if (!typeMap1 || !typeMap2)
141 return true;
142
143 for (var type in typeMap1) {
144 if (TypeMapHasType(typeMap1, type) && TypeMapHasType(typeMap2, type))
145 return false;
146 }
147
148 return true;
149 }
150
151
152 var defaultAcceptTypes = (function() {
153 var defaultTypes = [
154 'add',
155 'update',
156 'delete',
157 'setPrototype',
158 'reconfigure',
159 'preventExtensions'
160 ];
161 return TypeMapCreateFromList(defaultTypes, defaultTypes.length);
162 })();
163
164
165 // An Observer is a registration to observe an object by a callback with
166 // a given set of accept types. If the set of accept types is the default
167 // set for Object.observe, the observer is represented as a direct reference
168 // to the callback. An observer never changes its accept types and thus never
169 // needs to "normalize".
170 function ObserverCreate(callback, acceptList) {
171 if (IS_UNDEFINED(acceptList))
172 return callback;
173 var observer = nullProtoObject();
174 observer.callback = callback;
175 observer.accept = acceptList;
176 return observer;
177 }
178
179
180 function ObserverGetCallback(observer) {
181 return IS_CALLABLE(observer) ? observer : observer.callback;
182 }
183
184
185 function ObserverGetAcceptTypes(observer) {
186 return IS_CALLABLE(observer) ? defaultAcceptTypes : observer.accept;
187 }
188
189
190 function ObserverIsActive(observer, objectInfo) {
191 return TypeMapIsDisjointFrom(ObjectInfoGetPerformingTypes(objectInfo),
192 ObserverGetAcceptTypes(observer));
193 }
194
195
196 function ObjectInfoGetOrCreate(object) {
197 var objectInfo = ObjectInfoGet(object);
198 if (IS_UNDEFINED(objectInfo)) {
199 if (!%_IsJSProxy(object)) {
200 %SetIsObserved(object);
201 }
202 objectInfo = {
203 object: object,
204 changeObservers: null,
205 notifier: null,
206 performing: null,
207 performingCount: 0,
208 };
209 %WeakCollectionSet(GetObservationStateJS().objectInfoMap,
210 object, objectInfo, $getHash(object));
211 }
212 return objectInfo;
213 }
214
215
216 function ObjectInfoGet(object) {
217 return %WeakCollectionGet(GetObservationStateJS().objectInfoMap, object,
218 $getHash(object));
219 }
220
221
222 function ObjectInfoGetFromNotifier(notifier) {
223 return %WeakCollectionGet(GetObservationStateJS().notifierObjectInfoMap,
224 notifier, $getHash(notifier));
225 }
226
227
228 function ObjectInfoGetNotifier(objectInfo) {
229 if (IS_NULL(objectInfo.notifier)) {
230 var notifier = { __proto__: notifierPrototype };
231 objectInfo.notifier = notifier;
232 %WeakCollectionSet(GetObservationStateJS().notifierObjectInfoMap,
233 notifier, objectInfo, $getHash(notifier));
234 }
235
236 return objectInfo.notifier;
237 }
238
239
240 function ChangeObserversIsOptimized(changeObservers) {
241 return IS_CALLABLE(changeObservers) ||
242 IS_CALLABLE(changeObservers.callback);
243 }
244
245
246 // The set of observers on an object is called 'changeObservers'. The first
247 // observer is referenced directly via objectInfo.changeObservers. When a second
248 // is added, changeObservers "normalizes" to become a mapping of callback
249 // priority -> observer and is then stored on objectInfo.changeObservers.
250 function ObjectInfoNormalizeChangeObservers(objectInfo) {
251 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
252 var observer = objectInfo.changeObservers;
253 var callback = ObserverGetCallback(observer);
254 var callbackInfo = CallbackInfoGet(callback);
255 var priority = CallbackInfoGetPriority(callbackInfo);
256 objectInfo.changeObservers = nullProtoObject();
257 objectInfo.changeObservers[priority] = observer;
258 }
259 }
260
261
262 function ObjectInfoAddObserver(objectInfo, callback, acceptList) {
263 var callbackInfo = CallbackInfoGetOrCreate(callback);
264 var observer = ObserverCreate(callback, acceptList);
265
266 if (!objectInfo.changeObservers) {
267 objectInfo.changeObservers = observer;
268 return;
269 }
270
271 ObjectInfoNormalizeChangeObservers(objectInfo);
272 var priority = CallbackInfoGetPriority(callbackInfo);
273 objectInfo.changeObservers[priority] = observer;
274 }
275
276 function ObjectInfoRemoveObserver(objectInfo, callback) {
277 if (!objectInfo.changeObservers)
278 return;
279
280 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
281 if (callback === ObserverGetCallback(objectInfo.changeObservers))
282 objectInfo.changeObservers = null;
283 return;
284 }
285
286 var callbackInfo = CallbackInfoGet(callback);
287 var priority = CallbackInfoGetPriority(callbackInfo);
288 objectInfo.changeObservers[priority] = null;
289 }
290
291 function ObjectInfoHasActiveObservers(objectInfo) {
292 if (IS_UNDEFINED(objectInfo) || !objectInfo.changeObservers)
293 return false;
294
295 if (ChangeObserversIsOptimized(objectInfo.changeObservers))
296 return ObserverIsActive(objectInfo.changeObservers, objectInfo);
297
298 for (var priority in objectInfo.changeObservers) {
299 var observer = objectInfo.changeObservers[priority];
300 if (!IS_NULL(observer) && ObserverIsActive(observer, objectInfo))
301 return true;
302 }
303
304 return false;
305 }
306
307
308 function ObjectInfoAddPerformingType(objectInfo, type) {
309 objectInfo.performing = objectInfo.performing || TypeMapCreate();
310 TypeMapAddType(objectInfo.performing, type);
311 objectInfo.performingCount++;
312 }
313
314
315 function ObjectInfoRemovePerformingType(objectInfo, type) {
316 objectInfo.performingCount--;
317 TypeMapRemoveType(objectInfo.performing, type);
318 }
319
320
321 function ObjectInfoGetPerformingTypes(objectInfo) {
322 return objectInfo.performingCount > 0 ? objectInfo.performing : null;
323 }
324
325
326 function ConvertAcceptListToTypeMap(arg) {
327 // We use undefined as a sentinel for the default accept list.
328 if (IS_UNDEFINED(arg))
329 return arg;
330
331 if (!IS_SPEC_OBJECT(arg)) throw MakeTypeError(kObserveInvalidAccept);
332
333 var len = TO_INTEGER(arg.length);
334 if (len < 0) len = 0;
335
336 return TypeMapCreateFromList(arg, len);
337 }
338
339
340 // CallbackInfo's optimized state is just a number which represents its global
341 // priority. When a change record must be enqueued for the callback, it
342 // normalizes. When delivery clears any pending change records, it re-optimizes.
343 function CallbackInfoGet(callback) {
344 return %WeakCollectionGet(GetObservationStateJS().callbackInfoMap, callback,
345 $getHash(callback));
346 }
347
348
349 function CallbackInfoSet(callback, callbackInfo) {
350 %WeakCollectionSet(GetObservationStateJS().callbackInfoMap,
351 callback, callbackInfo, $getHash(callback));
352 }
353
354
355 function CallbackInfoGetOrCreate(callback) {
356 var callbackInfo = CallbackInfoGet(callback);
357 if (!IS_UNDEFINED(callbackInfo))
358 return callbackInfo;
359
360 var priority = GetNextCallbackPriority();
361 CallbackInfoSet(callback, priority);
362 return priority;
363 }
364
365
366 function CallbackInfoGetPriority(callbackInfo) {
367 if (IS_NUMBER(callbackInfo))
368 return callbackInfo;
369 else
370 return callbackInfo.priority;
371 }
372
373
374 function CallbackInfoNormalize(callback) {
375 var callbackInfo = CallbackInfoGet(callback);
376 if (IS_NUMBER(callbackInfo)) {
377 var priority = callbackInfo;
378 callbackInfo = new InternalArray;
379 callbackInfo.priority = priority;
380 CallbackInfoSet(callback, callbackInfo);
381 }
382 return callbackInfo;
383 }
384
385
386 function ObjectObserve(object, callback, acceptList) {
387 if (!IS_SPEC_OBJECT(object))
388 throw MakeTypeError(kObserveNonObject, "observe", "observe");
389 if (%IsJSGlobalProxy(object))
390 throw MakeTypeError(kObserveGlobalProxy, "observe");
391 if (%IsAccessCheckNeeded(object))
392 throw MakeTypeError(kObserveAccessChecked, "observe");
393 if (!IS_CALLABLE(callback))
394 throw MakeTypeError(kObserveNonFunction, "observe");
395 if (ObjectIsFrozen(callback))
396 throw MakeTypeError(kObserveCallbackFrozen);
397
398 var objectObserveFn = %GetObjectContextObjectObserve(object);
399 return objectObserveFn(object, callback, acceptList);
400 }
401
402
403 function NativeObjectObserve(object, callback, acceptList) {
404 var objectInfo = ObjectInfoGetOrCreate(object);
405 var typeList = ConvertAcceptListToTypeMap(acceptList);
406 ObjectInfoAddObserver(objectInfo, callback, typeList);
407 return object;
408 }
409
410
411 function ObjectUnobserve(object, callback) {
412 if (!IS_SPEC_OBJECT(object))
413 throw MakeTypeError(kObserveNonObject, "unobserve", "unobserve");
414 if (%IsJSGlobalProxy(object))
415 throw MakeTypeError(kObserveGlobalProxy, "unobserve");
416 if (!IS_CALLABLE(callback))
417 throw MakeTypeError(kObserveNonFunction, "unobserve");
418
419 var objectInfo = ObjectInfoGet(object);
420 if (IS_UNDEFINED(objectInfo))
421 return object;
422
423 ObjectInfoRemoveObserver(objectInfo, callback);
424 return object;
425 }
426
427
428 function ArrayObserve(object, callback) {
429 return ObjectObserve(object, callback, ['add',
430 'update',
431 'delete',
432 'splice']);
433 }
434
435
436 function ArrayUnobserve(object, callback) {
437 return ObjectUnobserve(object, callback);
438 }
439
440
441 function ObserverEnqueueIfActive(observer, objectInfo, changeRecord) {
442 if (!ObserverIsActive(observer, objectInfo) ||
443 !TypeMapHasType(ObserverGetAcceptTypes(observer), changeRecord.type)) {
444 return;
445 }
446
447 var callback = ObserverGetCallback(observer);
448 if (!%ObserverObjectAndRecordHaveSameOrigin(callback, changeRecord.object,
449 changeRecord)) {
450 return;
451 }
452
453 var callbackInfo = CallbackInfoNormalize(callback);
454 if (IS_NULL(GetPendingObservers())) {
455 SetPendingObservers(nullProtoObject());
456 if (DEBUG_IS_ACTIVE) {
457 var id = ++GetObservationStateJS().lastMicrotaskId;
458 var name = "Object.observe";
459 %EnqueueMicrotask(function() {
460 %DebugAsyncTaskEvent({ type: "willHandle", id: id, name: name });
461 ObserveMicrotaskRunner();
462 %DebugAsyncTaskEvent({ type: "didHandle", id: id, name: name });
463 });
464 %DebugAsyncTaskEvent({ type: "enqueue", id: id, name: name });
465 } else {
466 %EnqueueMicrotask(ObserveMicrotaskRunner);
467 }
468 }
469 GetPendingObservers()[callbackInfo.priority] = callback;
470 callbackInfo.push(changeRecord);
471 }
472
473
474 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) {
475 if (!ObjectInfoHasActiveObservers(objectInfo))
476 return;
477
478 var hasType = !IS_UNDEFINED(type);
479 var newRecord = hasType ?
480 { object: objectInfo.object, type: type } :
481 { object: objectInfo.object };
482
483 for (var prop in changeRecord) {
484 if (prop === 'object' || (hasType && prop === 'type')) continue;
485 %DefineDataPropertyUnchecked(
486 newRecord, prop, changeRecord[prop], READ_ONLY + DONT_DELETE);
487 }
488 ObjectFreeze(newRecord);
489
490 ObjectInfoEnqueueInternalChangeRecord(objectInfo, newRecord);
491 }
492
493
494 function ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord) {
495 // TODO(rossberg): adjust once there is a story for symbols vs proxies.
496 if (IS_SYMBOL(changeRecord.name)) return;
497
498 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) {
499 var observer = objectInfo.changeObservers;
500 ObserverEnqueueIfActive(observer, objectInfo, changeRecord);
501 return;
502 }
503
504 for (var priority in objectInfo.changeObservers) {
505 var observer = objectInfo.changeObservers[priority];
506 if (IS_NULL(observer))
507 continue;
508 ObserverEnqueueIfActive(observer, objectInfo, changeRecord);
509 }
510 }
511
512
513 function BeginPerformSplice(array) {
514 var objectInfo = ObjectInfoGet(array);
515 if (!IS_UNDEFINED(objectInfo))
516 ObjectInfoAddPerformingType(objectInfo, 'splice');
517 }
518
519
520 function EndPerformSplice(array) {
521 var objectInfo = ObjectInfoGet(array);
522 if (!IS_UNDEFINED(objectInfo))
523 ObjectInfoRemovePerformingType(objectInfo, 'splice');
524 }
525
526
527 function EnqueueSpliceRecord(array, index, removed, addedCount) {
528 var objectInfo = ObjectInfoGet(array);
529 if (!ObjectInfoHasActiveObservers(objectInfo))
530 return;
531
532 var changeRecord = {
533 type: 'splice',
534 object: array,
535 index: index,
536 removed: removed,
537 addedCount: addedCount
538 };
539
540 ObjectFreeze(changeRecord);
541 ObjectFreeze(changeRecord.removed);
542 ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
543 }
544
545
546 function NotifyChange(type, object, name, oldValue) {
547 var objectInfo = ObjectInfoGet(object);
548 if (!ObjectInfoHasActiveObservers(objectInfo))
549 return;
550
551 var changeRecord;
552 if (arguments.length == 2) {
553 changeRecord = { type: type, object: object };
554 } else if (arguments.length == 3) {
555 changeRecord = { type: type, object: object, name: name };
556 } else {
557 changeRecord = {
558 type: type,
559 object: object,
560 name: name,
561 oldValue: oldValue
562 };
563 }
564
565 ObjectFreeze(changeRecord);
566 ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord);
567 }
568
569
570 function ObjectNotifierNotify(changeRecord) {
571 if (!IS_SPEC_OBJECT(this))
572 throw MakeTypeError(kCalledOnNonObject, "notify");
573
574 var objectInfo = ObjectInfoGetFromNotifier(this);
575 if (IS_UNDEFINED(objectInfo))
576 throw MakeTypeError(kObserveNotifyNonNotifier);
577 if (!IS_STRING(changeRecord.type))
578 throw MakeTypeError(kObserveTypeNonString);
579
580 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord);
581 }
582
583
584 function ObjectNotifierPerformChange(changeType, changeFn) {
585 if (!IS_SPEC_OBJECT(this))
586 throw MakeTypeError(kCalledOnNonObject, "performChange");
587
588 var objectInfo = ObjectInfoGetFromNotifier(this);
589 if (IS_UNDEFINED(objectInfo))
590 throw MakeTypeError(kObserveNotifyNonNotifier);
591 if (!IS_STRING(changeType))
592 throw MakeTypeError(kObservePerformNonString);
593 if (!IS_CALLABLE(changeFn))
594 throw MakeTypeError(kObservePerformNonFunction);
595
596 var performChangeFn = %GetObjectContextNotifierPerformChange(objectInfo);
597 performChangeFn(objectInfo, changeType, changeFn);
598 }
599
600
601 function NativeObjectNotifierPerformChange(objectInfo, changeType, changeFn) {
602 ObjectInfoAddPerformingType(objectInfo, changeType);
603
604 var changeRecord;
605 try {
606 changeRecord = changeFn();
607 } finally {
608 ObjectInfoRemovePerformingType(objectInfo, changeType);
609 }
610
611 if (IS_SPEC_OBJECT(changeRecord))
612 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType);
613 }
614
615
616 function ObjectGetNotifier(object) {
617 if (!IS_SPEC_OBJECT(object))
618 throw MakeTypeError(kObserveNonObject, "getNotifier", "getNotifier");
619 if (%IsJSGlobalProxy(object))
620 throw MakeTypeError(kObserveGlobalProxy, "getNotifier");
621 if (%IsAccessCheckNeeded(object))
622 throw MakeTypeError(kObserveAccessChecked, "getNotifier");
623
624 if (ObjectIsFrozen(object)) return null;
625
626 if (!%ObjectWasCreatedInCurrentOrigin(object)) return null;
627
628 var getNotifierFn = %GetObjectContextObjectGetNotifier(object);
629 return getNotifierFn(object);
630 }
631
632
633 function NativeObjectGetNotifier(object) {
634 var objectInfo = ObjectInfoGetOrCreate(object);
635 return ObjectInfoGetNotifier(objectInfo);
636 }
637
638
639 function CallbackDeliverPending(callback) {
640 var callbackInfo = CallbackInfoGet(callback);
641 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo))
642 return false;
643
644 // Clear the pending change records from callback and return it to its
645 // "optimized" state.
646 var priority = callbackInfo.priority;
647 CallbackInfoSet(callback, priority);
648
649 var pendingObservers = GetPendingObservers();
650 if (!IS_NULL(pendingObservers))
651 delete pendingObservers[priority];
652
653 // TODO: combine the following runtime calls for perf optimization.
654 var delivered = [];
655 %MoveArrayContents(callbackInfo, delivered);
656 %DeliverObservationChangeRecords(callback, delivered);
657
658 return true;
659 }
660
661
662 function ObjectDeliverChangeRecords(callback) {
663 if (!IS_CALLABLE(callback))
664 throw MakeTypeError(kObserveNonFunction, "deliverChangeRecords");
665
666 while (CallbackDeliverPending(callback)) {}
667 }
668
669
670 function ObserveMicrotaskRunner() {
671 var pendingObservers = GetPendingObservers();
672 if (!IS_NULL(pendingObservers)) {
673 SetPendingObservers(null);
674 for (var i in pendingObservers) {
675 CallbackDeliverPending(pendingObservers[i]);
676 }
677 }
678 }
679
680 // -------------------------------------------------------------------
681
682 utils.InstallFunctions(notifierPrototype, DONT_ENUM, [
683 "notify", ObjectNotifierNotify,
684 "performChange", ObjectNotifierPerformChange
685 ]);
686
687 $observeObjectMethods = [
688 "deliverChangeRecords", ObjectDeliverChangeRecords,
689 "getNotifier", ObjectGetNotifier,
690 "observe", ObjectObserve,
691 "unobserve", ObjectUnobserve
692 ];
693 $observeArrayMethods = [
694 "observe", ArrayObserve,
695 "unobserve", ArrayUnobserve
696 ];
697
698 // TODO(adamk): Figure out why this prototype removal has to
699 // happen as part of initial snapshotting.
700 var removePrototypeFn = function(f, i) {
701 if (i % 2 === 1) %FunctionRemovePrototype(f);
702 };
703 $observeObjectMethods.forEach(removePrototypeFn);
704 $observeArrayMethods.forEach(removePrototypeFn);
705
706 $observeEnqueueSpliceRecord = EnqueueSpliceRecord;
707 $observeBeginPerformSplice = BeginPerformSplice;
708 $observeEndPerformSplice = EndPerformSplice;
709
710 %InstallToContext([
711 "native_object_get_notifier", NativeObjectGetNotifier,
712 "native_object_notifier_perform_change", NativeObjectNotifierPerformChange,
713 "native_object_observe", NativeObjectObserve,
714 "observers_begin_perform_splice", BeginPerformSplice,
715 "observers_end_perform_splice", EndPerformSplice,
716 "observers_enqueue_splice", EnqueueSpliceRecord,
717 "observers_notify_change", NotifyChange,
718 ]);
719
720 })
OLDNEW
« no previous file with comments | « src/messages.js ('k') | src/prologue.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698