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

Side by Side Diff: src/keys.cc

Issue 1963633002: [keys] fixing nested JSProxy for-in enumeration (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 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
« no previous file with comments | « src/keys.h ('k') | test/mjsunit/es6/proxies-for.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
106 return AddKey(handle(key, isolate_), convert); 106 return AddKey(handle(key, isolate_), convert);
107 } 107 }
108 108
109 bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) { 109 bool KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
110 if (key->IsSymbol()) { 110 if (key->IsSymbol()) {
111 if (filter_ & SKIP_SYMBOLS) return false; 111 if (filter_ & SKIP_SYMBOLS) return false;
112 if (Handle<Symbol>::cast(key)->is_private()) return false; 112 if (Handle<Symbol>::cast(key)->is_private()) return false;
113 return AddSymbolKey(key); 113 return AddSymbolKey(key);
114 } 114 }
115 if (filter_ & SKIP_STRINGS) return false; 115 if (filter_ & SKIP_STRINGS) return false;
116 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). 116 // Make sure we do not add keys to a proxy-level (see AddKeysFromJSProxy).
117 DCHECK_LE(0, level_string_length_); 117 DCHECK_LE(0, level_string_length_);
118 // In some cases (e.g. proxies) we might get in String-converted ints which 118 // In some cases (e.g. proxies) we might get in String-converted ints which
119 // should be added to the elements list instead of the properties. For 119 // should be added to the elements list instead of the properties. For
120 // proxies we have to convert as well but also respect the original order. 120 // proxies we have to convert as well but also respect the original order.
121 // Therefore we add a converted key to both sides 121 // Therefore we add a converted key to both sides
122 if (convert == CONVERT_TO_ARRAY_INDEX || convert == PROXY_MAGIC) { 122 if (convert == CONVERT_TO_ARRAY_INDEX || convert == PROXY_MAGIC) {
123 uint32_t index = 0; 123 uint32_t index = 0;
124 int prev_length = length_; 124 int prev_length = length_;
125 int prev_proto = level_string_length_; 125 int prev_proto = level_string_length_;
126 if ((key->IsString() && Handle<String>::cast(key)->AsArrayIndex(&index)) || 126 if ((key->IsString() && Handle<String>::cast(key)->AsArrayIndex(&index)) ||
(...skipping 11 matching lines...) Expand all
138 level_string_length_ = prev_proto; 138 level_string_length_ = prev_proto;
139 } 139 }
140 } 140 }
141 } 141 }
142 return AddStringKey(key, convert); 142 return AddStringKey(key, convert);
143 } 143 }
144 144
145 bool KeyAccumulator::AddKey(uint32_t key) { return AddIntegerKey(key); } 145 bool KeyAccumulator::AddKey(uint32_t key) { return AddIntegerKey(key); }
146 146
147 bool KeyAccumulator::AddIntegerKey(uint32_t key) { 147 bool KeyAccumulator::AddIntegerKey(uint32_t key) {
148 // Make sure we do not add keys to a proxy-level (see AddKeysFromProxy). 148 // Make sure we do not add keys to a proxy-level (see AddKeysFromJSProxy).
149 // We mark proxy-levels with a negative length 149 // We mark proxy-levels with a negative length
150 DCHECK_LE(0, level_string_length_); 150 DCHECK_LE(0, level_string_length_);
151 // Binary search over all but the last level. The last one might not be 151 // Binary search over all but the last level. The last one might not be
152 // sorted yet. 152 // sorted yet.
153 for (size_t i = 1; i < elements_.size(); i++) { 153 for (size_t i = 1; i < elements_.size(); i++) {
154 if (AccumulatorHasKey(elements_[i - 1], key)) return false; 154 if (AccumulatorHasKey(elements_[i - 1], key)) return false;
155 } 155 }
156 elements_.back()->push_back(key); 156 elements_.back()->push_back(key);
157 length_++; 157 length_++;
158 return true; 158 return true;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 } 204 }
205 } 205 }
206 206
207 void KeyAccumulator::AddKeys(Handle<JSObject> array_like, 207 void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
208 AddKeyConversion convert) { 208 AddKeyConversion convert) {
209 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements()); 209 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
210 ElementsAccessor* accessor = array_like->GetElementsAccessor(); 210 ElementsAccessor* accessor = array_like->GetElementsAccessor();
211 accessor->AddElementsToKeyAccumulator(array_like, this, convert); 211 accessor->AddElementsToKeyAccumulator(array_like, this, convert);
212 } 212 }
213 213
214 void KeyAccumulator::AddKeysFromProxy(Handle<JSObject> array_like) {
215 // Proxies define a complete list of keys with no distinction of
216 // elements and properties, which breaks the normal assumption for the
217 // KeyAccumulator.
218 AddKeys(array_like, PROXY_MAGIC);
219 // Invert the current length to indicate a present proxy, so we can ignore
220 // element keys for this level. Otherwise we would not fully respect the order
221 // given by the proxy.
222 level_string_length_ = -level_string_length_;
223 }
224
225 MaybeHandle<FixedArray> FilterProxyKeys(Isolate* isolate, Handle<JSProxy> owner, 214 MaybeHandle<FixedArray> FilterProxyKeys(Isolate* isolate, Handle<JSProxy> owner,
226 Handle<FixedArray> keys, 215 Handle<FixedArray> keys,
227 PropertyFilter filter) { 216 PropertyFilter filter) {
228 if (filter == ALL_PROPERTIES) { 217 if (filter == ALL_PROPERTIES) {
229 // Nothing to do. 218 // Nothing to do.
230 return keys; 219 return keys;
231 } 220 }
232 int store_position = 0; 221 int store_position = 0;
233 for (int i = 0; i < keys->length(); ++i) { 222 for (int i = 0; i < keys->length(); ++i) {
234 Handle<Name> key(Name::cast(keys->get(i)), isolate); 223 Handle<Name> key(Name::cast(keys->get(i)), isolate);
(...skipping 10 matching lines...) Expand all
245 keys->set(store_position, *key); 234 keys->set(store_position, *key);
246 } 235 }
247 store_position++; 236 store_position++;
248 } 237 }
249 if (store_position == 0) return isolate->factory()->empty_fixed_array(); 238 if (store_position == 0) return isolate->factory()->empty_fixed_array();
250 keys->Shrink(store_position); 239 keys->Shrink(store_position);
251 return keys; 240 return keys;
252 } 241 }
253 242
254 // Returns "nothing" in case of exception, "true" on success. 243 // Returns "nothing" in case of exception, "true" on success.
255 Maybe<bool> KeyAccumulator::AddKeysFromProxy(Handle<JSProxy> proxy, 244 Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy,
256 Handle<FixedArray> keys) { 245 Handle<FixedArray> keys) {
257 if (filter_proxy_keys_) { 246 if (filter_proxy_keys_) {
258 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 247 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
259 isolate_, keys, FilterProxyKeys(isolate_, proxy, keys, filter_), 248 isolate_, keys, FilterProxyKeys(isolate_, proxy, keys, filter_),
260 Nothing<bool>()); 249 Nothing<bool>());
261 } 250 }
262 // Proxies define a complete list of keys with no distinction of 251 // Proxies define a complete list of keys with no distinction of
263 // elements and properties, which breaks the normal assumption for the 252 // elements and properties, which breaks the normal assumption for the
264 // KeyAccumulator. 253 // KeyAccumulator.
265 if (type_ == OWN_ONLY) { 254 if (type_ == OWN_ONLY) {
266 ownProxyKeys_ = keys; 255 ownProxyKeys_ = keys;
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after
641 PropertyDetails details = descs->GetDetails(i); 630 PropertyDetails details = descs->GetDetails(i);
642 if ((details.attributes() & filter_) != 0) continue; 631 if ((details.attributes() & filter_) != 0) continue;
643 if (filter_ & ONLY_ALL_CAN_READ) { 632 if (filter_ & ONLY_ALL_CAN_READ) {
644 if (details.kind() != kAccessor) continue; 633 if (details.kind() != kAccessor) continue;
645 Object* accessors = descs->GetValue(i); 634 Object* accessors = descs->GetValue(i);
646 if (!accessors->IsAccessorInfo()) continue; 635 if (!accessors->IsAccessorInfo()) continue;
647 if (!AccessorInfo::cast(accessors)->all_can_read()) continue; 636 if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
648 } 637 }
649 Name* key = descs->GetKey(i); 638 Name* key = descs->GetKey(i);
650 if (key->FilterKey(filter_)) continue; 639 if (key->FilterKey(filter_)) continue;
651 this->AddKey(key, DO_NOT_CONVERT); 640 AddKey(key, DO_NOT_CONVERT);
652 } 641 }
653 } else if (object->IsJSGlobalObject()) { 642 } else if (object->IsJSGlobalObject()) {
654 GlobalDictionary::CollectKeysTo( 643 GlobalDictionary::CollectKeysTo(
655 handle(object->global_dictionary(), isolate_), this, filter_); 644 handle(object->global_dictionary(), isolate_), this, filter_);
656 } else { 645 } else {
657 NameDictionary::CollectKeysTo( 646 NameDictionary::CollectKeysTo(
658 handle(object->property_dictionary(), isolate_), this, filter_); 647 handle(object->property_dictionary(), isolate_), this, filter_);
659 } 648 }
660 } 649 }
661 650
662 // Returns |true| on success, |false| if prototype walking should be stopped, 651 // Returns |true| on success, |false| if prototype walking should be stopped,
663 // |nothing| if an exception was thrown. 652 // |nothing| if an exception was thrown.
664 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, 653 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
665 Handle<JSObject> object) { 654 Handle<JSObject> object) {
666 this->NextPrototype(); 655 NextPrototype();
667 // Check access rights if required. 656 // Check access rights if required.
668 if (object->IsAccessCheckNeeded() && 657 if (object->IsAccessCheckNeeded() &&
669 !isolate_->MayAccess(handle(isolate_->context()), object)) { 658 !isolate_->MayAccess(handle(isolate_->context()), object)) {
670 // The cross-origin spec says that [[Enumerate]] shall return an empty 659 // The cross-origin spec says that [[Enumerate]] shall return an empty
671 // iterator when it doesn't have access... 660 // iterator when it doesn't have access...
672 if (type_ == INCLUDE_PROTOS) { 661 if (type_ == INCLUDE_PROTOS) {
673 return Just(false); 662 return Just(false);
674 } 663 }
675 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. 664 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties.
676 DCHECK_EQ(OWN_ONLY, type_); 665 DCHECK_EQ(OWN_ONLY, type_);
677 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); 666 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
678 } 667 }
679 668
680 this->CollectOwnElementIndices(object); 669 CollectOwnElementIndices(object);
681 670
682 // Add the element keys from the interceptor. 671 // Add the element keys from the interceptor.
683 Maybe<bool> success = 672 Maybe<bool> success =
684 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>( 673 GetKeysFromInterceptor<v8::IndexedPropertyEnumeratorCallback, kIndexed>(
685 receiver, object, this); 674 receiver, object, this);
686 MAYBE_RETURN(success, Nothing<bool>()); 675 MAYBE_RETURN(success, Nothing<bool>());
687 676
688 if (filter_ == ENUMERABLE_STRINGS) { 677 if (filter_ == ENUMERABLE_STRINGS) {
689 Handle<FixedArray> enum_keys = 678 Handle<FixedArray> enum_keys =
690 KeyAccumulator::GetEnumPropertyKeys(isolate_, object); 679 KeyAccumulator::GetEnumPropertyKeys(isolate_, object);
691 this->AddKeys(enum_keys, DO_NOT_CONVERT); 680 AddKeys(enum_keys, DO_NOT_CONVERT);
692 } else { 681 } else {
693 this->CollectOwnPropertyNames(object); 682 CollectOwnPropertyNames(object);
694 } 683 }
695 684
696 // Add the property keys from the interceptor. 685 // Add the property keys from the interceptor.
697 success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback, 686 success = GetKeysFromInterceptor<v8::GenericNamedPropertyEnumeratorCallback,
698 kNamed>(receiver, object, this); 687 kNamed>(receiver, object, this);
699 MAYBE_RETURN(success, Nothing<bool>()); 688 MAYBE_RETURN(success, Nothing<bool>());
700 return Just(true); 689 return Just(true);
701 } 690 }
702 691
703 // static 692 // static
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
744 Handle<JSReceiver> target(proxy->target(), isolate_); 733 Handle<JSReceiver> target(proxy->target(), isolate_);
745 // 5. Let trap be ? GetMethod(handler, "ownKeys"). 734 // 5. Let trap be ? GetMethod(handler, "ownKeys").
746 Handle<Object> trap; 735 Handle<Object> trap;
747 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 736 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
748 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), 737 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
749 isolate_->factory()->ownKeys_string()), 738 isolate_->factory()->ownKeys_string()),
750 Nothing<bool>()); 739 Nothing<bool>());
751 // 6. If trap is undefined, then 740 // 6. If trap is undefined, then
752 if (trap->IsUndefined()) { 741 if (trap->IsUndefined()) {
753 // 6a. Return target.[[OwnPropertyKeys]](). 742 // 6a. Return target.[[OwnPropertyKeys]]().
754 KeyCollectionType previous_type = type_; 743 return CollectOwnJSProxyTargetKeys(proxy, target);
755 type_ = OWN_ONLY;
756 Maybe<bool> result = this->CollectKeys(receiver, target);
757 type_ = previous_type;
758 return result;
759 } 744 }
760 // 7. Let trapResultArray be Call(trap, handler, «target»). 745 // 7. Let trapResultArray be Call(trap, handler, «target»).
761 Handle<Object> trap_result_array; 746 Handle<Object> trap_result_array;
762 Handle<Object> args[] = {target}; 747 Handle<Object> args[] = {target};
763 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 748 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
764 isolate_, trap_result_array, 749 isolate_, trap_result_array,
765 Execution::Call(isolate_, trap, handler, arraysize(args), args), 750 Execution::Call(isolate_, trap, handler, arraysize(args), args),
766 Nothing<bool>()); 751 Nothing<bool>());
767 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, 752 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
768 // «String, Symbol»). 753 // «String, Symbol»).
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
803 target_keys->get(i)); 788 target_keys->get(i));
804 nonconfigurable_keys_length++; 789 nonconfigurable_keys_length++;
805 // The key was moved, null it out in the original list. 790 // The key was moved, null it out in the original list.
806 target_keys->set(i, Smi::FromInt(0)); 791 target_keys->set(i, Smi::FromInt(0));
807 } else { 792 } else {
808 // 14c. Else, 793 // 14c. Else,
809 // 14c i. Append key as an element of targetConfigurableKeys. 794 // 14c i. Append key as an element of targetConfigurableKeys.
810 // (No-op, just keep it in |target_keys|.) 795 // (No-op, just keep it in |target_keys|.)
811 } 796 }
812 } 797 }
813 this->NextPrototype(); // Prepare for accumulating keys. 798 NextPrototype(); // Prepare for accumulating keys.
814 // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty, 799 // 15. If extensibleTarget is true and targetNonconfigurableKeys is empty,
815 // then: 800 // then:
816 if (extensible_target && nonconfigurable_keys_length == 0) { 801 if (extensible_target && nonconfigurable_keys_length == 0) {
817 // 15a. Return trapResult. 802 // 15a. Return trapResult.
818 return this->AddKeysFromProxy(proxy, trap_result); 803 return AddKeysFromJSProxy(proxy, trap_result);
819 } 804 }
820 // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult. 805 // 16. Let uncheckedResultKeys be a new List which is a copy of trapResult.
821 Zone set_zone(isolate_->allocator()); 806 Zone set_zone(isolate_->allocator());
822 const int kPresent = 1; 807 const int kPresent = 1;
823 const int kGone = 0; 808 const int kGone = 0;
824 IdentityMap<int> unchecked_result_keys(isolate_->heap(), &set_zone); 809 IdentityMap<int> unchecked_result_keys(isolate_->heap(), &set_zone);
825 int unchecked_result_keys_size = 0; 810 int unchecked_result_keys_size = 0;
826 for (int i = 0; i < trap_result->length(); ++i) { 811 for (int i = 0; i < trap_result->length(); ++i) {
827 DCHECK(trap_result->get(i)->IsUniqueName()); 812 DCHECK(trap_result->get(i)->IsUniqueName());
828 Object* key = trap_result->get(i); 813 Object* key = trap_result->get(i);
(...skipping 13 matching lines...) Expand all
842 isolate_->Throw(*isolate_->factory()->NewTypeError( 827 isolate_->Throw(*isolate_->factory()->NewTypeError(
843 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_))); 828 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_)));
844 return Nothing<bool>(); 829 return Nothing<bool>();
845 } 830 }
846 // 17b. Remove key from uncheckedResultKeys. 831 // 17b. Remove key from uncheckedResultKeys.
847 *found = kGone; 832 *found = kGone;
848 unchecked_result_keys_size--; 833 unchecked_result_keys_size--;
849 } 834 }
850 // 18. If extensibleTarget is true, return trapResult. 835 // 18. If extensibleTarget is true, return trapResult.
851 if (extensible_target) { 836 if (extensible_target) {
852 return this->AddKeysFromProxy(proxy, trap_result); 837 return AddKeysFromJSProxy(proxy, trap_result);
853 } 838 }
854 // 19. Repeat, for each key that is an element of targetConfigurableKeys: 839 // 19. Repeat, for each key that is an element of targetConfigurableKeys:
855 for (int i = 0; i < target_configurable_keys->length(); ++i) { 840 for (int i = 0; i < target_configurable_keys->length(); ++i) {
856 Object* key = target_configurable_keys->get(i); 841 Object* key = target_configurable_keys->get(i);
857 if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable. 842 if (key->IsSmi()) continue; // Zapped entry, was nonconfigurable.
858 // 19a. If key is not an element of uncheckedResultKeys, throw a 843 // 19a. If key is not an element of uncheckedResultKeys, throw a
859 // TypeError exception. 844 // TypeError exception.
860 int* found = unchecked_result_keys.Find(key); 845 int* found = unchecked_result_keys.Find(key);
861 if (found == nullptr || *found == kGone) { 846 if (found == nullptr || *found == kGone) {
862 isolate_->Throw(*isolate_->factory()->NewTypeError( 847 isolate_->Throw(*isolate_->factory()->NewTypeError(
863 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_))); 848 MessageTemplate::kProxyOwnKeysMissing, handle(key, isolate_)));
864 return Nothing<bool>(); 849 return Nothing<bool>();
865 } 850 }
866 // 19b. Remove key from uncheckedResultKeys. 851 // 19b. Remove key from uncheckedResultKeys.
867 *found = kGone; 852 *found = kGone;
868 unchecked_result_keys_size--; 853 unchecked_result_keys_size--;
869 } 854 }
870 // 20. If uncheckedResultKeys is not empty, throw a TypeError exception. 855 // 20. If uncheckedResultKeys is not empty, throw a TypeError exception.
871 if (unchecked_result_keys_size != 0) { 856 if (unchecked_result_keys_size != 0) {
872 DCHECK_GT(unchecked_result_keys_size, 0); 857 DCHECK_GT(unchecked_result_keys_size, 0);
873 isolate_->Throw(*isolate_->factory()->NewTypeError( 858 isolate_->Throw(*isolate_->factory()->NewTypeError(
874 MessageTemplate::kProxyOwnKeysNonExtensible)); 859 MessageTemplate::kProxyOwnKeysNonExtensible));
875 return Nothing<bool>(); 860 return Nothing<bool>();
876 } 861 }
877 // 21. Return trapResult. 862 // 21. Return trapResult.
878 return this->AddKeysFromProxy(proxy, trap_result); 863 return AddKeysFromJSProxy(proxy, trap_result);
864 }
865
866 Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys(
867 Handle<JSProxy> proxy, Handle<JSReceiver> target) {
868 // TODO(cbruni): avoid creating another KeyAccumulator
869 Handle<FixedArray> keys;
870 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
871 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>());
872 NextPrototype(); // Prepare for accumulating keys.
873 bool prev_filter_proxy_keys_ = filter_proxy_keys_;
874 filter_proxy_keys_ = false;
875 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);
876 filter_proxy_keys_ = prev_filter_proxy_keys_;
877 return result;
879 } 878 }
880 879
881 } // namespace internal 880 } // namespace internal
882 } // namespace v8 881 } // namespace v8
OLDNEW
« no previous file with comments | « src/keys.h ('k') | test/mjsunit/es6/proxies-for.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698