OLD | NEW |
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 337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
348 callbackInfo = new InternalArray; | 348 callbackInfo = new InternalArray; |
349 callbackInfo.priority = priority; | 349 callbackInfo.priority = priority; |
350 GetCallbackInfoMap().set(callback, callbackInfo); | 350 GetCallbackInfoMap().set(callback, callbackInfo); |
351 } | 351 } |
352 return callbackInfo; | 352 return callbackInfo; |
353 } | 353 } |
354 | 354 |
355 function ObjectObserve(object, callback, acceptList) { | 355 function ObjectObserve(object, callback, acceptList) { |
356 if (!IS_SPEC_OBJECT(object)) | 356 if (!IS_SPEC_OBJECT(object)) |
357 throw MakeTypeError("observe_non_object", ["observe"]); | 357 throw MakeTypeError("observe_non_object", ["observe"]); |
| 358 if (%IsJSGlobalProxy(object)) |
| 359 throw MakeTypeError("observe_global_proxy", ["observe"]); |
358 if (!IS_SPEC_FUNCTION(callback)) | 360 if (!IS_SPEC_FUNCTION(callback)) |
359 throw MakeTypeError("observe_non_function", ["observe"]); | 361 throw MakeTypeError("observe_non_function", ["observe"]); |
360 if (ObjectIsFrozen(callback)) | 362 if (ObjectIsFrozen(callback)) |
361 throw MakeTypeError("observe_callback_frozen"); | 363 throw MakeTypeError("observe_callback_frozen"); |
362 if (!AcceptArgIsValid(acceptList)) | 364 if (!AcceptArgIsValid(acceptList)) |
363 throw MakeTypeError("observe_accept_invalid"); | 365 throw MakeTypeError("observe_accept_invalid"); |
364 | 366 |
365 var objectInfo = ObjectInfoGetOrCreate(object); | 367 var objectInfo = ObjectInfoGetOrCreate(object); |
366 ObjectInfoAddObserver(objectInfo, callback, acceptList); | 368 ObjectInfoAddObserver(objectInfo, callback, acceptList); |
367 return object; | 369 return object; |
368 } | 370 } |
369 | 371 |
370 function ObjectUnobserve(object, callback) { | 372 function ObjectUnobserve(object, callback) { |
371 if (!IS_SPEC_OBJECT(object)) | 373 if (!IS_SPEC_OBJECT(object)) |
372 throw MakeTypeError("observe_non_object", ["unobserve"]); | 374 throw MakeTypeError("observe_non_object", ["unobserve"]); |
| 375 if (%IsJSGlobalProxy(object)) |
| 376 throw MakeTypeError("observe_global_proxy", ["unobserve"]); |
373 if (!IS_SPEC_FUNCTION(callback)) | 377 if (!IS_SPEC_FUNCTION(callback)) |
374 throw MakeTypeError("observe_non_function", ["unobserve"]); | 378 throw MakeTypeError("observe_non_function", ["unobserve"]); |
375 | 379 |
376 var objectInfo = ObjectInfoGet(object); | 380 var objectInfo = ObjectInfoGet(object); |
377 if (IS_UNDEFINED(objectInfo)) | 381 if (IS_UNDEFINED(objectInfo)) |
378 return object; | 382 return object; |
379 | 383 |
380 ObjectInfoRemoveObserver(objectInfo, callback); | 384 ObjectInfoRemoveObserver(objectInfo, callback); |
381 return object; | 385 return object; |
382 } | 386 } |
383 | 387 |
384 function ArrayObserve(object, callback) { | 388 function ArrayObserve(object, callback) { |
385 return ObjectObserve(object, callback, ['add', | 389 return ObjectObserve(object, callback, ['add', |
386 'update', | 390 'update', |
387 'delete', | 391 'delete', |
388 'splice']); | 392 'splice']); |
389 } | 393 } |
390 | 394 |
391 function ArrayUnobserve(object, callback) { | 395 function ArrayUnobserve(object, callback) { |
392 return ObjectUnobserve(object, callback); | 396 return ObjectUnobserve(object, callback); |
393 } | 397 } |
394 | 398 |
395 function ObserverEnqueueIfActive(observer, objectInfo, changeRecord, | 399 function ObserverEnqueueIfActive(observer, objectInfo, changeRecord) { |
396 needsAccessCheck) { | |
397 if (!ObserverIsActive(observer, objectInfo) || | 400 if (!ObserverIsActive(observer, objectInfo) || |
398 !TypeMapHasType(ObserverGetAcceptTypes(observer), changeRecord.type)) { | 401 !TypeMapHasType(ObserverGetAcceptTypes(observer), changeRecord.type)) { |
399 return; | 402 return; |
400 } | 403 } |
401 | 404 |
402 var callback = ObserverGetCallback(observer); | 405 var callback = ObserverGetCallback(observer); |
403 if (needsAccessCheck && | 406 if (!%ObserverObjectAndRecordHaveSameOrigin(callback, changeRecord.object, |
404 // Drop all splice records on the floor for access-checked objects | 407 changeRecord)) { |
405 (changeRecord.type == 'splice' || | |
406 !%IsAccessAllowedForObserver( | |
407 callback, changeRecord.object, changeRecord.name))) { | |
408 return; | 408 return; |
409 } | 409 } |
410 | 410 |
411 var callbackInfo = CallbackInfoNormalize(callback); | 411 var callbackInfo = CallbackInfoNormalize(callback); |
412 if (IS_NULL(GetPendingObservers())) { | 412 if (IS_NULL(GetPendingObservers())) { |
413 SetPendingObservers(nullProtoObject()) | 413 SetPendingObservers(nullProtoObject()) |
414 GetMicrotaskQueue().push(ObserveMicrotaskRunner); | 414 GetMicrotaskQueue().push(ObserveMicrotaskRunner); |
415 %SetMicrotaskPending(true); | 415 %SetMicrotaskPending(true); |
416 } | 416 } |
417 GetPendingObservers()[callbackInfo.priority] = callback; | 417 GetPendingObservers()[callbackInfo.priority] = callback; |
418 callbackInfo.push(changeRecord); | 418 callbackInfo.push(changeRecord); |
419 } | 419 } |
420 | 420 |
421 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) { | 421 function ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, type) { |
422 if (!ObjectInfoHasActiveObservers(objectInfo)) | 422 if (!ObjectInfoHasActiveObservers(objectInfo)) |
423 return; | 423 return; |
424 | 424 |
425 var hasType = !IS_UNDEFINED(type); | 425 var hasType = !IS_UNDEFINED(type); |
426 var newRecord = hasType ? | 426 var newRecord = hasType ? |
427 { object: ObjectInfoGetObject(objectInfo), type: type } : | 427 { object: ObjectInfoGetObject(objectInfo), type: type } : |
428 { object: ObjectInfoGetObject(objectInfo) }; | 428 { object: ObjectInfoGetObject(objectInfo) }; |
429 | 429 |
430 for (var prop in changeRecord) { | 430 for (var prop in changeRecord) { |
431 if (prop === 'object' || (hasType && prop === 'type')) continue; | 431 if (prop === 'object' || (hasType && prop === 'type')) continue; |
432 %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop], | 432 %DefineOrRedefineDataProperty(newRecord, prop, changeRecord[prop], |
433 READ_ONLY + DONT_DELETE); | 433 READ_ONLY + DONT_DELETE); |
434 } | 434 } |
435 ObjectFreeze(newRecord); | 435 ObjectFreeze(newRecord); |
436 | 436 |
437 ObjectInfoEnqueueInternalChangeRecord(objectInfo, newRecord, | 437 ObjectInfoEnqueueInternalChangeRecord(objectInfo, newRecord); |
438 true /* skip access check */); | |
439 } | 438 } |
440 | 439 |
441 function ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord, | 440 function ObjectInfoEnqueueInternalChangeRecord(objectInfo, changeRecord) { |
442 skipAccessCheck) { | |
443 // TODO(rossberg): adjust once there is a story for symbols vs proxies. | 441 // TODO(rossberg): adjust once there is a story for symbols vs proxies. |
444 if (IS_SYMBOL(changeRecord.name)) return; | 442 if (IS_SYMBOL(changeRecord.name)) return; |
445 | 443 |
446 var needsAccessCheck = !skipAccessCheck && | |
447 %IsAccessCheckNeeded(changeRecord.object); | |
448 | |
449 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { | 444 if (ChangeObserversIsOptimized(objectInfo.changeObservers)) { |
450 var observer = objectInfo.changeObservers; | 445 var observer = objectInfo.changeObservers; |
451 ObserverEnqueueIfActive(observer, objectInfo, changeRecord, | 446 ObserverEnqueueIfActive(observer, objectInfo, changeRecord); |
452 needsAccessCheck); | |
453 return; | 447 return; |
454 } | 448 } |
455 | 449 |
456 for (var priority in objectInfo.changeObservers) { | 450 for (var priority in objectInfo.changeObservers) { |
457 var observer = objectInfo.changeObservers[priority]; | 451 var observer = objectInfo.changeObservers[priority]; |
458 if (IS_NULL(observer)) | 452 if (IS_NULL(observer)) |
459 continue; | 453 continue; |
460 ObserverEnqueueIfActive(observer, objectInfo, changeRecord, | 454 ObserverEnqueueIfActive(observer, objectInfo, changeRecord); |
461 needsAccessCheck); | |
462 } | 455 } |
463 } | 456 } |
464 | 457 |
465 function BeginPerformSplice(array) { | 458 function BeginPerformSplice(array) { |
466 var objectInfo = ObjectInfoGet(array); | 459 var objectInfo = ObjectInfoGet(array); |
467 if (!IS_UNDEFINED(objectInfo)) | 460 if (!IS_UNDEFINED(objectInfo)) |
468 ObjectInfoAddPerformingType(objectInfo, 'splice'); | 461 ObjectInfoAddPerformingType(objectInfo, 'splice'); |
469 } | 462 } |
470 | 463 |
471 function EndPerformSplice(array) { | 464 function EndPerformSplice(array) { |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
552 ObjectInfoRemovePerformingType(objectInfo, changeType); | 545 ObjectInfoRemovePerformingType(objectInfo, changeType); |
553 } | 546 } |
554 | 547 |
555 if (IS_SPEC_OBJECT(changeRecord)) | 548 if (IS_SPEC_OBJECT(changeRecord)) |
556 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType); | 549 ObjectInfoEnqueueExternalChangeRecord(objectInfo, changeRecord, changeType); |
557 } | 550 } |
558 | 551 |
559 function ObjectGetNotifier(object) { | 552 function ObjectGetNotifier(object) { |
560 if (!IS_SPEC_OBJECT(object)) | 553 if (!IS_SPEC_OBJECT(object)) |
561 throw MakeTypeError("observe_non_object", ["getNotifier"]); | 554 throw MakeTypeError("observe_non_object", ["getNotifier"]); |
| 555 if (%IsJSGlobalProxy(object)) |
| 556 throw MakeTypeError("observe_global_proxy", ["getNotifier"]); |
562 | 557 |
563 if (ObjectIsFrozen(object)) return null; | 558 if (ObjectIsFrozen(object)) return null; |
564 | 559 |
| 560 if (!%ObjectWasCreatedInCurrentOrigin(object)) return null; |
| 561 |
565 var objectInfo = ObjectInfoGetOrCreate(object); | 562 var objectInfo = ObjectInfoGetOrCreate(object); |
566 return ObjectInfoGetNotifier(objectInfo); | 563 return ObjectInfoGetNotifier(objectInfo); |
567 } | 564 } |
568 | 565 |
569 function CallbackDeliverPending(callback) { | 566 function CallbackDeliverPending(callback) { |
570 var callbackInfo = GetCallbackInfoMap().get(callback); | 567 var callbackInfo = GetCallbackInfoMap().get(callback); |
571 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo)) | 568 if (IS_UNDEFINED(callbackInfo) || IS_NUMBER(callbackInfo)) |
572 return false; | 569 return false; |
573 | 570 |
574 // Clear the pending change records from callback and return it to its | 571 // Clear the pending change records from callback and return it to its |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 InstallFunctions($Array, DONT_ENUM, $Array( | 613 InstallFunctions($Array, DONT_ENUM, $Array( |
617 "observe", ArrayObserve, | 614 "observe", ArrayObserve, |
618 "unobserve", ArrayUnobserve | 615 "unobserve", ArrayUnobserve |
619 )); | 616 )); |
620 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( | 617 InstallFunctions(notifierPrototype, DONT_ENUM, $Array( |
621 "notify", ObjectNotifierNotify, | 618 "notify", ObjectNotifierNotify, |
622 "performChange", ObjectNotifierPerformChange | 619 "performChange", ObjectNotifierPerformChange |
623 )); | 620 )); |
624 } | 621 } |
625 | 622 |
626 // Disable Object.observe API for M35. | 623 SetupObjectObserve(); |
627 // SetupObjectObserve(); | |
OLD | NEW |