| 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 |