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 |