OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 #include "src/keys.h" | 5 #include "src/keys.h" |
6 | 6 |
7 #include "src/api-arguments.h" | 7 #include "src/api-arguments.h" |
8 #include "src/elements.h" | 8 #include "src/elements.h" |
9 #include "src/factory.h" | 9 #include "src/factory.h" |
10 #include "src/identity-map.h" | 10 #include "src/identity-map.h" |
(...skipping 416 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
427 namespace { | 427 namespace { |
428 | 428 |
429 enum IndexedOrNamed { kIndexed, kNamed }; | 429 enum IndexedOrNamed { kIndexed, kNamed }; |
430 | 430 |
431 // Returns |true| on success, |nothing| on exception. | 431 // Returns |true| on success, |nothing| on exception. |
432 template <class Callback, IndexedOrNamed type> | 432 template <class Callback, IndexedOrNamed type> |
433 Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver, | 433 Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver, |
434 Handle<JSObject> object, | 434 Handle<JSObject> object, |
435 KeyAccumulator* accumulator) { | 435 KeyAccumulator* accumulator) { |
436 Isolate* isolate = accumulator->isolate(); | 436 Isolate* isolate = accumulator->isolate(); |
437 if (type == kIndexed) { | 437 Handle<InterceptorInfo> interceptor; |
438 if (!object->HasIndexedInterceptor()) return Just(true); | 438 if ((accumulator->filter() & USE_ACCESS_CHECK_INTERCEPTOR) && |
439 object->IsAccessCheckNeeded()) { | |
440 DisallowHeapAllocation no_gc; | |
441 AccessCheckInfo* access_check_info = AccessCheckInfo::Get(isolate, object); | |
442 if (!access_check_info) return Just(true); | |
443 Object* maybe_interceptor = type == kIndexed | |
444 ? access_check_info->indexed_interceptor() | |
445 : access_check_info->named_interceptor(); | |
446 if (!maybe_interceptor) return Just(true); | |
447 interceptor = handle(InterceptorInfo::cast(maybe_interceptor), isolate); | |
439 } else { | 448 } else { |
440 if (!object->HasNamedInterceptor()) return Just(true); | 449 if (type == kIndexed) { |
441 } | 450 if (!object->HasIndexedInterceptor()) return Just(true); |
442 Handle<InterceptorInfo> interceptor(type == kIndexed | 451 } else { |
443 ? object->GetIndexedInterceptor() | 452 if (!object->HasNamedInterceptor()) return Just(true); |
453 } | |
454 interceptor = handle(type == kIndexed ? object->GetIndexedInterceptor() | |
444 : object->GetNamedInterceptor(), | 455 : object->GetNamedInterceptor(), |
445 isolate); | 456 isolate); |
446 if ((accumulator->filter() & ONLY_ALL_CAN_READ) && | 457 if ((accumulator->filter() & ONLY_ALL_CAN_READ) && |
447 !interceptor->all_can_read()) { | 458 !interceptor->all_can_read()) { |
448 return Just(true); | 459 return Just(true); |
460 } | |
449 } | 461 } |
450 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, | 462 PropertyCallbackArguments args(isolate, interceptor->data(), *receiver, |
451 *object, Object::DONT_THROW); | 463 *object, Object::DONT_THROW); |
452 Handle<JSObject> result; | 464 Handle<JSObject> result; |
453 if (!interceptor->enumerator()->IsUndefined(isolate)) { | 465 if (!interceptor->enumerator()->IsUndefined(isolate)) { |
454 Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator()); | 466 Callback enum_fun = v8::ToCData<Callback>(interceptor->enumerator()); |
455 const char* log_tag = type == kIndexed ? "interceptor-indexed-enum" | 467 const char* log_tag = type == kIndexed ? "interceptor-indexed-enum" |
456 : "interceptor-named-enum"; | 468 : "interceptor-named-enum"; |
457 LOG(isolate, ApiObjectAccess(log_tag, *object)); | 469 LOG(isolate, ApiObjectAccess(log_tag, *object)); |
458 result = args.Call(enum_fun); | 470 result = args.Call(enum_fun); |
(...skipping 18 matching lines...) Expand all Loading... | |
477 kIndexed>(receiver, object, this); | 489 kIndexed>(receiver, object, this); |
478 } | 490 } |
479 | 491 |
480 namespace { | 492 namespace { |
481 | 493 |
482 template <bool skip_symbols> | 494 template <bool skip_symbols> |
483 int CollectOwnPropertyNamesInternal(Handle<JSObject> object, | 495 int CollectOwnPropertyNamesInternal(Handle<JSObject> object, |
484 KeyAccumulator* keys, | 496 KeyAccumulator* keys, |
485 Handle<DescriptorArray> descs, | 497 Handle<DescriptorArray> descs, |
486 int start_index, int limit) { | 498 int start_index, int limit) { |
499 DCHECK(!(keys->filter() & USE_ACCESS_CHECK_INTERCEPTOR)); | |
487 int first_skipped = -1; | 500 int first_skipped = -1; |
488 for (int i = start_index; i < limit; i++) { | 501 for (int i = start_index; i < limit; i++) { |
489 PropertyDetails details = descs->GetDetails(i); | 502 PropertyDetails details = descs->GetDetails(i); |
490 if ((details.attributes() & keys->filter()) != 0) continue; | 503 if ((details.attributes() & keys->filter()) != 0) continue; |
491 if (keys->filter() & ONLY_ALL_CAN_READ) { | 504 if (keys->filter() & ONLY_ALL_CAN_READ) { |
492 if (details.kind() != kAccessor) continue; | 505 if (details.kind() != kAccessor) continue; |
493 Object* accessors = descs->GetValue(i); | 506 Object* accessors = descs->GetValue(i); |
494 if (!accessors->IsAccessorInfo()) continue; | 507 if (!accessors->IsAccessorInfo()) continue; |
495 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; | 508 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; |
496 } | 509 } |
497 Name* key = descs->GetKey(i); | 510 Name* key = descs->GetKey(i); |
498 if (skip_symbols == key->IsSymbol()) { | 511 if (skip_symbols == key->IsSymbol()) { |
499 if (first_skipped == -1) first_skipped = i; | 512 if (first_skipped == -1) first_skipped = i; |
500 continue; | 513 continue; |
501 } | 514 } |
502 if (key->FilterKey(keys->filter())) continue; | 515 if (key->FilterKey(keys->filter())) continue; |
503 keys->AddKey(key, DO_NOT_CONVERT); | 516 keys->AddKey(key, DO_NOT_CONVERT); |
504 } | 517 } |
505 return first_skipped; | 518 return first_skipped; |
506 } | 519 } |
507 | 520 |
508 } // namespace | 521 } // namespace |
509 | 522 |
510 Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver, | 523 Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver, |
511 Handle<JSObject> object) { | 524 Handle<JSObject> object) { |
512 if (filter_ == ENUMERABLE_STRINGS) { | 525 if (filter_ == ENUMERABLE_STRINGS) { |
513 Handle<FixedArray> enum_keys = | 526 Handle<FixedArray> enum_keys = |
514 KeyAccumulator::GetEnumPropertyKeys(isolate_, object); | 527 KeyAccumulator::GetEnumPropertyKeys(isolate_, object); |
515 AddKeys(enum_keys, DO_NOT_CONVERT); | 528 AddKeys(enum_keys, DO_NOT_CONVERT); |
516 } else { | 529 } else if (!(filter_ & USE_ACCESS_CHECK_INTERCEPTOR)) { |
517 if (object->HasFastProperties()) { | 530 if (object->HasFastProperties()) { |
518 int limit = object->map()->NumberOfOwnDescriptors(); | 531 int limit = object->map()->NumberOfOwnDescriptors(); |
519 Handle<DescriptorArray> descs(object->map()->instance_descriptors(), | 532 Handle<DescriptorArray> descs(object->map()->instance_descriptors(), |
520 isolate_); | 533 isolate_); |
521 // First collect the strings, | 534 // First collect the strings, |
522 int first_symbol = | 535 int first_symbol = |
523 CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit); | 536 CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit); |
524 // then the symbols. | 537 // then the symbols. |
525 if (first_symbol != -1) { | 538 if (first_symbol != -1) { |
526 CollectOwnPropertyNamesInternal<false>(object, this, descs, | 539 CollectOwnPropertyNamesInternal<false>(object, this, descs, |
(...skipping 12 matching lines...) Expand all Loading... | |
539 kNamed>(receiver, object, this); | 552 kNamed>(receiver, object, this); |
540 } | 553 } |
541 | 554 |
542 // Returns |true| on success, |false| if prototype walking should be stopped, | 555 // Returns |true| on success, |false| if prototype walking should be stopped, |
543 // |nothing| if an exception was thrown. | 556 // |nothing| if an exception was thrown. |
544 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, | 557 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, |
545 Handle<JSObject> object) { | 558 Handle<JSObject> object) { |
546 // Check access rights if required. | 559 // Check access rights if required. |
547 if (object->IsAccessCheckNeeded() && | 560 if (object->IsAccessCheckNeeded() && |
548 !isolate_->MayAccess(handle(isolate_->context()), object)) { | 561 !isolate_->MayAccess(handle(isolate_->context()), object)) { |
562 DisallowHeapAllocation no_gc; | |
563 | |
549 // The cross-origin spec says that [[Enumerate]] shall return an empty | 564 // The cross-origin spec says that [[Enumerate]] shall return an empty |
550 // iterator when it doesn't have access... | 565 // iterator when it doesn't have access... |
551 if (mode_ == KeyCollectionMode::kIncludePrototypes) { | 566 if (mode_ == KeyCollectionMode::kIncludePrototypes) { |
552 return Just(false); | 567 return Just(false); |
553 } | 568 } |
554 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. | 569 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. |
555 DCHECK(KeyCollectionMode::kOwnOnly == mode_); | 570 DCHECK(KeyCollectionMode::kOwnOnly == mode_); |
556 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); | 571 AccessCheckInfo* access_check_info = AccessCheckInfo::Get(isolate_, object); |
572 // We always either have both a named and an indexed interceptor or none. | |
573 if (!access_check_info || !access_check_info->named_interceptor()) { | |
574 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); | |
575 } else { | |
576 filter_ = | |
577 static_cast<PropertyFilter>(filter_ | USE_ACCESS_CHECK_INTERCEPTOR); | |
Toon Verwaest
2016/06/27 09:34:58
We should get rid of these filters. Just duplicate
Toon Verwaest
2016/06/27 09:37:59
I think you basically want to reuse the lower half
| |
578 } | |
557 } | 579 } |
558 MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>()); | 580 MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>()); |
559 MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>()); | 581 MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>()); |
560 return Just(true); | 582 return Just(true); |
561 } | 583 } |
562 | 584 |
563 // static | 585 // static |
564 Handle<FixedArray> KeyAccumulator::GetEnumPropertyKeys( | 586 Handle<FixedArray> KeyAccumulator::GetEnumPropertyKeys( |
565 Isolate* isolate, Handle<JSObject> object) { | 587 Isolate* isolate, Handle<JSObject> object) { |
588 DCHECK(!object->IsAccessCheckNeeded() || | |
589 isolate->MayAccess(handle(isolate->context()), object)); | |
566 if (object->HasFastProperties()) { | 590 if (object->HasFastProperties()) { |
567 return GetFastEnumPropertyKeys(isolate, object); | 591 return GetFastEnumPropertyKeys(isolate, object); |
568 } else if (object->IsJSGlobalObject()) { | 592 } else if (object->IsJSGlobalObject()) { |
569 Handle<GlobalDictionary> dictionary(object->global_dictionary(), isolate); | 593 Handle<GlobalDictionary> dictionary(object->global_dictionary(), isolate); |
570 int length = dictionary->NumberOfEnumElements(); | 594 int length = dictionary->NumberOfEnumElements(); |
571 if (length == 0) { | 595 if (length == 0) { |
572 return isolate->factory()->empty_fixed_array(); | 596 return isolate->factory()->empty_fixed_array(); |
573 } | 597 } |
574 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 598 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
575 dictionary->CopyEnumKeysTo(*storage); | 599 dictionary->CopyEnumKeysTo(*storage); |
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
741 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>()); | 765 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>()); |
742 bool prev_filter_proxy_keys_ = filter_proxy_keys_; | 766 bool prev_filter_proxy_keys_ = filter_proxy_keys_; |
743 filter_proxy_keys_ = false; | 767 filter_proxy_keys_ = false; |
744 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); | 768 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); |
745 filter_proxy_keys_ = prev_filter_proxy_keys_; | 769 filter_proxy_keys_ = prev_filter_proxy_keys_; |
746 return result; | 770 return result; |
747 } | 771 } |
748 | 772 |
749 } // namespace internal | 773 } // namespace internal |
750 } // namespace v8 | 774 } // namespace v8 |
OLD | NEW |