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 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |