| 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 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 // Store the protoLength on the first call of this method. | 307 // Store the protoLength on the first call of this method. |
| 308 if (!elements_.empty()) { | 308 if (!elements_.empty()) { |
| 309 level_lengths_.push_back(level_string_length_); | 309 level_lengths_.push_back(level_string_length_); |
| 310 level_lengths_.push_back(level_symbol_length_); | 310 level_lengths_.push_back(level_symbol_length_); |
| 311 } | 311 } |
| 312 elements_.push_back(new std::vector<uint32_t>()); | 312 elements_.push_back(new std::vector<uint32_t>()); |
| 313 level_string_length_ = 0; | 313 level_string_length_ = 0; |
| 314 level_symbol_length_ = 0; | 314 level_symbol_length_ = 0; |
| 315 } | 315 } |
| 316 | 316 |
| 317 Maybe<bool> KeyAccumulator::GetKeys_Internal(Handle<JSReceiver> receiver, | 317 Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, |
| 318 Handle<JSReceiver> object, | 318 Handle<JSReceiver> object) { |
| 319 KeyCollectionType type) { | |
| 320 // Proxies have no hidden prototype and we should not trigger the | 319 // Proxies have no hidden prototype and we should not trigger the |
| 321 // [[GetPrototypeOf]] trap on the last iteration when using | 320 // [[GetPrototypeOf]] trap on the last iteration when using |
| 322 // AdvanceFollowingProxies. | 321 // AdvanceFollowingProxies. |
| 323 if (type == OWN_ONLY && object->IsJSProxy()) { | 322 if (type_ == OWN_ONLY && object->IsJSProxy()) { |
| 324 MAYBE_RETURN( | 323 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)), |
| 325 JSProxyOwnPropertyKeys(receiver, Handle<JSProxy>::cast(object)), | 324 Nothing<bool>()); |
| 326 Nothing<bool>()); | |
| 327 return Just(true); | 325 return Just(true); |
| 328 } | 326 } |
| 329 | 327 |
| 330 PrototypeIterator::WhereToEnd end = type == OWN_ONLY | 328 PrototypeIterator::WhereToEnd end = type_ == OWN_ONLY |
| 331 ? PrototypeIterator::END_AT_NON_HIDDEN | 329 ? PrototypeIterator::END_AT_NON_HIDDEN |
| 332 : PrototypeIterator::END_AT_NULL; | 330 : PrototypeIterator::END_AT_NULL; |
| 333 for (PrototypeIterator iter(isolate_, object, | 331 for (PrototypeIterator iter(isolate_, object, |
| 334 PrototypeIterator::START_AT_RECEIVER, end); | 332 PrototypeIterator::START_AT_RECEIVER, end); |
| 335 !iter.IsAtEnd();) { | 333 !iter.IsAtEnd();) { |
| 336 Handle<JSReceiver> current = | 334 Handle<JSReceiver> current = |
| 337 PrototypeIterator::GetCurrent<JSReceiver>(iter); | 335 PrototypeIterator::GetCurrent<JSReceiver>(iter); |
| 338 Maybe<bool> result = Just(false); // Dummy initialization. | 336 Maybe<bool> result = Just(false); // Dummy initialization. |
| 339 if (current->IsJSProxy()) { | 337 if (current->IsJSProxy()) { |
| 340 result = JSProxyOwnPropertyKeys(receiver, Handle<JSProxy>::cast(current)); | 338 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current)); |
| 341 } else { | 339 } else { |
| 342 DCHECK(current->IsJSObject()); | 340 DCHECK(current->IsJSObject()); |
| 343 result = | 341 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current)); |
| 344 GetKeysFromJSObject(receiver, Handle<JSObject>::cast(current), type); | |
| 345 } | 342 } |
| 346 MAYBE_RETURN(result, Nothing<bool>()); | 343 MAYBE_RETURN(result, Nothing<bool>()); |
| 347 if (!result.FromJust()) break; // |false| means "stop iterating". | 344 if (!result.FromJust()) break; // |false| means "stop iterating". |
| 348 // Iterate through proxies but ignore access checks for the ALL_CAN_READ | 345 // Iterate through proxies but ignore access checks for the ALL_CAN_READ |
| 349 // case on API objects for OWN_ONLY keys handled in GetKeysFromJSObject. | 346 // case on API objects for OWN_ONLY keys handled in CollectOwnKeys. |
| 350 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) { | 347 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) { |
| 351 return Nothing<bool>(); | 348 return Nothing<bool>(); |
| 352 } | 349 } |
| 353 } | 350 } |
| 354 return Just(true); | 351 return Just(true); |
| 355 } | 352 } |
| 356 | 353 |
| 357 namespace { | 354 namespace { |
| 358 | 355 |
| 359 void TrySettingEmptyEnumCache(JSReceiver* object) { | 356 void TrySettingEmptyEnumCache(JSReceiver* object) { |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 622 DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements()); | 619 DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements()); |
| 623 // The accumulator takes care of string/symbol filtering. | 620 // The accumulator takes care of string/symbol filtering. |
| 624 if (type == kIndexed) { | 621 if (type == kIndexed) { |
| 625 accumulator->AddElementKeysFromInterceptor(result); | 622 accumulator->AddElementKeysFromInterceptor(result); |
| 626 } else { | 623 } else { |
| 627 accumulator->AddKeys(result, DO_NOT_CONVERT); | 624 accumulator->AddKeys(result, DO_NOT_CONVERT); |
| 628 } | 625 } |
| 629 return Just(true); | 626 return Just(true); |
| 630 } | 627 } |
| 631 | 628 |
| 632 void KeyAccumulator::CollectOwnElementKeys(Handle<JSObject> object) { | 629 void KeyAccumulator::CollectOwnElementIndices(Handle<JSObject> object) { |
| 633 if (filter_ & SKIP_STRINGS) return; | 630 if (filter_ & SKIP_STRINGS) return; |
| 634 ElementsAccessor* accessor = object->GetElementsAccessor(); | 631 ElementsAccessor* accessor = object->GetElementsAccessor(); |
| 635 accessor->CollectElementIndices(object, this, kMaxUInt32, filter_, 0); | 632 accessor->CollectElementIndices(object, this); |
| 636 } | 633 } |
| 637 | 634 |
| 638 void KeyAccumulator::CollectOwnPropertyNames(Handle<JSObject> object) { | 635 void KeyAccumulator::CollectOwnPropertyNames(Handle<JSObject> object) { |
| 639 if (object->HasFastProperties()) { | 636 if (object->HasFastProperties()) { |
| 640 int real_size = object->map()->NumberOfOwnDescriptors(); | 637 int real_size = object->map()->NumberOfOwnDescriptors(); |
| 641 Handle<DescriptorArray> descs(object->map()->instance_descriptors(), | 638 Handle<DescriptorArray> descs(object->map()->instance_descriptors(), |
| 642 isolate_); | 639 isolate_); |
| 643 for (int i = 0; i < real_size; i++) { | 640 for (int i = 0; i < real_size; i++) { |
| 644 PropertyDetails details = descs->GetDetails(i); | 641 PropertyDetails details = descs->GetDetails(i); |
| 645 if ((details.attributes() & filter_) != 0) continue; | 642 if ((details.attributes() & filter_) != 0) continue; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 657 GlobalDictionary::CollectKeysTo( | 654 GlobalDictionary::CollectKeysTo( |
| 658 handle(object->global_dictionary(), isolate_), this, filter_); | 655 handle(object->global_dictionary(), isolate_), this, filter_); |
| 659 } else { | 656 } else { |
| 660 NameDictionary::CollectKeysTo( | 657 NameDictionary::CollectKeysTo( |
| 661 handle(object->property_dictionary(), isolate_), this, filter_); | 658 handle(object->property_dictionary(), isolate_), this, filter_); |
| 662 } | 659 } |
| 663 } | 660 } |
| 664 | 661 |
| 665 // Returns |true| on success, |false| if prototype walking should be stopped, | 662 // Returns |true| on success, |false| if prototype walking should be stopped, |
| 666 // |nothing| if an exception was thrown. | 663 // |nothing| if an exception was thrown. |
| 667 Maybe<bool> KeyAccumulator::GetKeysFromJSObject(Handle<JSReceiver> receiver, | 664 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, |
| 668 Handle<JSObject> object, | 665 Handle<JSObject> object) { |
| 669 KeyCollectionType type) { | |
| 670 this->NextPrototype(); | 666 this->NextPrototype(); |
| 671 // Check access rights if required. | 667 // Check access rights if required. |
| 672 if (object->IsAccessCheckNeeded() && | 668 if (object->IsAccessCheckNeeded() && |
| 673 !isolate_->MayAccess(handle(isolate_->context()), object)) { | 669 !isolate_->MayAccess(handle(isolate_->context()), object)) { |
| 674 // The cross-origin spec says that [[Enumerate]] shall return an empty | 670 // The cross-origin spec says that [[Enumerate]] shall return an empty |
| 675 // iterator when it doesn't have access... | 671 // iterator when it doesn't have access... |
| 676 if (type == INCLUDE_PROTOS) { | 672 if (type_ == INCLUDE_PROTOS) { |
| 677 return Just(false); | 673 return Just(false); |
| 678 } | 674 } |
| 679 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. | 675 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. |
| 680 DCHECK_EQ(OWN_ONLY, type); | 676 DCHECK_EQ(OWN_ONLY, type_); |
| 681 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); | 677 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); |
| 682 } | 678 } |
| 683 | 679 |
| 684 this->CollectOwnElementKeys(object); | 680 this->CollectOwnElementIndices(object); |
| 685 | 681 |
| 686 // Add the element keys from the interceptor. | 682 // Add the element keys from the interceptor. |
| 687 Maybe<bool> success = | 683 Maybe<bool> success = |
| 688 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>( | 684 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>( |
| 689 receiver, object, this); | 685 receiver, object, this); |
| 690 MAYBE_RETURN(success, Nothing<bool>()); | 686 MAYBE_RETURN(success, Nothing<bool>()); |
| 691 | 687 |
| 692 if (filter_ == ENUMERABLE_STRINGS) { | 688 if (filter_ == ENUMERABLE_STRINGS) { |
| 693 Handle<FixedArray> enum_keys = | 689 Handle<FixedArray> enum_keys = |
| 694 KeyAccumulator::GetEnumPropertyKeys(isolate_, object); | 690 KeyAccumulator::GetEnumPropertyKeys(isolate_, object); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 725 return isolate->factory()->empty_fixed_array(); | 721 return isolate->factory()->empty_fixed_array(); |
| 726 } | 722 } |
| 727 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); | 723 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length); |
| 728 dictionary->CopyEnumKeysTo(*storage); | 724 dictionary->CopyEnumKeysTo(*storage); |
| 729 return storage; | 725 return storage; |
| 730 } | 726 } |
| 731 } | 727 } |
| 732 | 728 |
| 733 // ES6 9.5.12 | 729 // ES6 9.5.12 |
| 734 // Returns |true| on success, |nothing| in case of exception. | 730 // Returns |true| on success, |nothing| in case of exception. |
| 735 Maybe<bool> KeyAccumulator::JSProxyOwnPropertyKeys(Handle<JSReceiver> receiver, | 731 Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver, |
| 736 Handle<JSProxy> proxy) { | 732 Handle<JSProxy> proxy) { |
| 737 STACK_CHECK(isolate_, Nothing<bool>()); | 733 STACK_CHECK(isolate_, Nothing<bool>()); |
| 738 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. | 734 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. |
| 739 Handle<Object> handler(proxy->handler(), isolate_); | 735 Handle<Object> handler(proxy->handler(), isolate_); |
| 740 // 2. If handler is null, throw a TypeError exception. | 736 // 2. If handler is null, throw a TypeError exception. |
| 741 // 3. Assert: Type(handler) is Object. | 737 // 3. Assert: Type(handler) is Object. |
| 742 if (proxy->IsRevoked()) { | 738 if (proxy->IsRevoked()) { |
| 743 isolate_->Throw(*isolate_->factory()->NewTypeError( | 739 isolate_->Throw(*isolate_->factory()->NewTypeError( |
| 744 MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string())); | 740 MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string())); |
| 745 return Nothing<bool>(); | 741 return Nothing<bool>(); |
| 746 } | 742 } |
| 747 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O. | 743 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O. |
| 748 Handle<JSReceiver> target(proxy->target(), isolate_); | 744 Handle<JSReceiver> target(proxy->target(), isolate_); |
| 749 // 5. Let trap be ? GetMethod(handler, "ownKeys"). | 745 // 5. Let trap be ? GetMethod(handler, "ownKeys"). |
| 750 Handle<Object> trap; | 746 Handle<Object> trap; |
| 751 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 747 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 752 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), | 748 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), |
| 753 isolate_->factory()->ownKeys_string()), | 749 isolate_->factory()->ownKeys_string()), |
| 754 Nothing<bool>()); | 750 Nothing<bool>()); |
| 755 // 6. If trap is undefined, then | 751 // 6. If trap is undefined, then |
| 756 if (trap->IsUndefined()) { | 752 if (trap->IsUndefined()) { |
| 757 // 6a. Return target.[[OwnPropertyKeys]](). | 753 // 6a. Return target.[[OwnPropertyKeys]](). |
| 758 return this->GetKeys_Internal(receiver, target, OWN_ONLY); | 754 KeyCollectionType previous_type = type_; |
| 755 type_ = OWN_ONLY; |
| 756 Maybe<bool> result = this->CollectKeys(receiver, target); |
| 757 type_ = previous_type; |
| 758 return result; |
| 759 } | 759 } |
| 760 // 7. Let trapResultArray be Call(trap, handler, «target»). | 760 // 7. Let trapResultArray be Call(trap, handler, «target»). |
| 761 Handle<Object> trap_result_array; | 761 Handle<Object> trap_result_array; |
| 762 Handle<Object> args[] = {target}; | 762 Handle<Object> args[] = {target}; |
| 763 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 763 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 764 isolate_, trap_result_array, | 764 isolate_, trap_result_array, |
| 765 Execution::Call(isolate_, trap, handler, arraysize(args), args), | 765 Execution::Call(isolate_, trap, handler, arraysize(args), args), |
| 766 Nothing<bool>()); | 766 Nothing<bool>()); |
| 767 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, | 767 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, |
| 768 // «String, Symbol»). | 768 // «String, Symbol»). |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 873 isolate_->Throw(*isolate_->factory()->NewTypeError( | 873 isolate_->Throw(*isolate_->factory()->NewTypeError( |
| 874 MessageTemplate::kProxyOwnKeysNonExtensible)); | 874 MessageTemplate::kProxyOwnKeysNonExtensible)); |
| 875 return Nothing<bool>(); | 875 return Nothing<bool>(); |
| 876 } | 876 } |
| 877 // 21. Return trapResult. | 877 // 21. Return trapResult. |
| 878 return this->AddKeysFromProxy(proxy, trap_result); | 878 return this->AddKeysFromProxy(proxy, trap_result); |
| 879 } | 879 } |
| 880 | 880 |
| 881 } // namespace internal | 881 } // namespace internal |
| 882 } // namespace v8 | 882 } // namespace v8 |
| OLD | NEW |