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

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

Issue 265503002: Re-enable Object.observe and add enforcement for security invariants. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: throw on Observe or getNotifier with global object Created 6 years, 7 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/messages.js ('k') | src/objects.h » ('j') | src/objects.cc » ('J')
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 337 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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();
OLDNEW
« no previous file with comments | « src/messages.js ('k') | src/objects.h » ('j') | src/objects.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698