Chromium Code Reviews| 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 |