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 20 matching lines...) Expand all Loading... | |
| 31 } | 31 } | 
| 32 | 32 | 
| 33 } // namespace | 33 } // namespace | 
| 34 MaybeHandle<FixedArray> KeyAccumulator::GetKeys( | 34 MaybeHandle<FixedArray> KeyAccumulator::GetKeys( | 
| 35 Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter, | 35 Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter, | 
| 36 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) { | 36 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) { | 
| 37 Isolate* isolate = object->GetIsolate(); | 37 Isolate* isolate = object->GetIsolate(); | 
| 38 KeyAccumulator accumulator(isolate, mode, filter); | 38 KeyAccumulator accumulator(isolate, mode, filter); | 
| 39 accumulator.set_filter_proxy_keys(filter_proxy_keys); | 39 accumulator.set_filter_proxy_keys(filter_proxy_keys); | 
| 40 accumulator.set_is_for_in(is_for_in); | 40 accumulator.set_is_for_in(is_for_in); | 
| 41 MAYBE_RETURN(accumulator.CollectKeys(object, object), | 41 MAYBE_RETURN(accumulator.CollectKeys(object, object, keys_conversion), | 
| 42 MaybeHandle<FixedArray>()); | 42 MaybeHandle<FixedArray>()); | 
| 43 return accumulator.GetKeys(keys_conversion); | 43 return accumulator.GetKeys(keys_conversion); | 
| 44 } | 44 } | 
| 45 | 45 | 
| 46 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { | 46 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { | 
| 47 if (keys_.is_null()) { | 47 if (keys_.is_null()) { | 
| 48 return isolate_->factory()->empty_fixed_array(); | 48 return isolate_->factory()->empty_fixed_array(); | 
| 49 } | 49 } | 
| 50 if (mode_ == KeyCollectionMode::kOwnOnly && | 50 if (mode_ == KeyCollectionMode::kOwnOnly && | 
| 51 keys_->map() == isolate_->heap()->fixed_array_map()) { | 51 keys_->map() == isolate_->heap()->fixed_array_map()) { | 
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 144 if (mode_ == KeyCollectionMode::kOwnOnly && !is_for_in_) { | 144 if (mode_ == KeyCollectionMode::kOwnOnly && !is_for_in_) { | 
| 145 // If we collect only the keys from a JSProxy do not sort or deduplicate it. | 145 // If we collect only the keys from a JSProxy do not sort or deduplicate it. | 
| 146 keys_ = keys; | 146 keys_ = keys; | 
| 147 return Just(true); | 147 return Just(true); | 
| 148 } | 148 } | 
| 149 AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT); | 149 AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT); | 
| 150 return Just(true); | 150 return Just(true); | 
| 151 } | 151 } | 
| 152 | 152 | 
| 153 Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, | 153 Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, | 
| 154 Handle<JSReceiver> object) { | 154 Handle<JSReceiver> object, | 
| 155 GetKeysConversion keys_conversion) { | |
| 155 // Proxies have no hidden prototype and we should not trigger the | 156 // Proxies have no hidden prototype and we should not trigger the | 
| 156 // [[GetPrototypeOf]] trap on the last iteration when using | 157 // [[GetPrototypeOf]] trap on the last iteration when using | 
| 157 // AdvanceFollowingProxies. | 158 // AdvanceFollowingProxies. | 
| 158 if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) { | 159 if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) { | 
| 159 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)), | 160 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object), | 
| 161 keys_conversion), | |
| 160 Nothing<bool>()); | 162 Nothing<bool>()); | 
| 161 return Just(true); | 163 return Just(true); | 
| 162 } | 164 } | 
| 163 | 165 | 
| 164 PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly | 166 PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly | 
| 165 ? PrototypeIterator::END_AT_NON_HIDDEN | 167 ? PrototypeIterator::END_AT_NON_HIDDEN | 
| 166 : PrototypeIterator::END_AT_NULL; | 168 : PrototypeIterator::END_AT_NULL; | 
| 167 for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end); | 169 for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end); | 
| 168 !iter.IsAtEnd();) { | 170 !iter.IsAtEnd();) { | 
| 169 Handle<JSReceiver> current = | 171 Handle<JSReceiver> current = | 
| 170 PrototypeIterator::GetCurrent<JSReceiver>(iter); | 172 PrototypeIterator::GetCurrent<JSReceiver>(iter); | 
| 171 Maybe<bool> result = Just(false); // Dummy initialization. | 173 Maybe<bool> result = Just(false); // Dummy initialization. | 
| 172 if (current->IsJSProxy()) { | 174 if (current->IsJSProxy()) { | 
| 173 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current)); | 175 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current), | 
| 176 keys_conversion); | |
| 174 } else { | 177 } else { | 
| 175 DCHECK(current->IsJSObject()); | 178 DCHECK(current->IsJSObject()); | 
| 176 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current)); | 179 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current)); | 
| 177 } | 180 } | 
| 178 MAYBE_RETURN(result, Nothing<bool>()); | 181 MAYBE_RETURN(result, Nothing<bool>()); | 
| 179 if (!result.FromJust()) break; // |false| means "stop iterating". | 182 if (!result.FromJust()) break; // |false| means "stop iterating". | 
| 180 // Iterate through proxies but ignore access checks for the ALL_CAN_READ | 183 // Iterate through proxies but ignore access checks for the ALL_CAN_READ | 
| 181 // case on API objects for OWN_ONLY keys handled in CollectOwnKeys. | 184 // case on API objects for OWN_ONLY keys handled in CollectOwnKeys. | 
| 182 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) { | 185 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) { | 
| 183 return Nothing<bool>(); | 186 return Nothing<bool>(); | 
| (...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 696 object->global_dictionary()); | 699 object->global_dictionary()); | 
| 697 } else { | 700 } else { | 
| 698 return GetOwnEnumPropertyDictionaryKeys( | 701 return GetOwnEnumPropertyDictionaryKeys( | 
| 699 isolate, KeyCollectionMode::kOwnOnly, nullptr, object, | 702 isolate, KeyCollectionMode::kOwnOnly, nullptr, object, | 
| 700 object->property_dictionary()); | 703 object->property_dictionary()); | 
| 701 } | 704 } | 
| 702 } | 705 } | 
| 703 | 706 | 
| 704 // ES6 9.5.12 | 707 // ES6 9.5.12 | 
| 705 // Returns |true| on success, |nothing| in case of exception. | 708 // Returns |true| on success, |nothing| in case of exception. | 
| 706 Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver, | 709 Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys( | 
| 707 Handle<JSProxy> proxy) { | 710 Handle<JSReceiver> receiver, Handle<JSProxy> proxy, | 
| 711 GetKeysConversion keys_conversion) { | |
| 708 STACK_CHECK(isolate_, Nothing<bool>()); | 712 STACK_CHECK(isolate_, Nothing<bool>()); | 
| 709 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. | 713 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O. | 
| 710 Handle<Object> handler(proxy->handler(), isolate_); | 714 Handle<Object> handler(proxy->handler(), isolate_); | 
| 711 // 2. If handler is null, throw a TypeError exception. | 715 // 2. If handler is null, throw a TypeError exception. | 
| 712 // 3. Assert: Type(handler) is Object. | 716 // 3. Assert: Type(handler) is Object. | 
| 713 if (proxy->IsRevoked()) { | 717 if (proxy->IsRevoked()) { | 
| 714 isolate_->Throw(*isolate_->factory()->NewTypeError( | 718 isolate_->Throw(*isolate_->factory()->NewTypeError( | 
| 715 MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string())); | 719 MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string())); | 
| 716 return Nothing<bool>(); | 720 return Nothing<bool>(); | 
| 717 } | 721 } | 
| 718 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O. | 722 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O. | 
| 719 Handle<JSReceiver> target(proxy->target(), isolate_); | 723 Handle<JSReceiver> target(proxy->target(), isolate_); | 
| 720 // 5. Let trap be ? GetMethod(handler, "ownKeys"). | 724 // 5. Let trap be ? GetMethod(handler, "ownKeys"). | 
| 721 Handle<Object> trap; | 725 Handle<Object> trap; | 
| 722 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 726 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
| 723 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), | 727 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler), | 
| 724 isolate_->factory()->ownKeys_string()), | 728 isolate_->factory()->ownKeys_string()), | 
| 725 Nothing<bool>()); | 729 Nothing<bool>()); | 
| 726 // 6. If trap is undefined, then | 730 // 6. If trap is undefined, then | 
| 727 if (trap->IsUndefined(isolate_)) { | 731 if (trap->IsUndefined(isolate_)) { | 
| 728 // 6a. Return target.[[OwnPropertyKeys]](). | 732 // 6a. Return target.[[OwnPropertyKeys]](). | 
| 729 return CollectOwnJSProxyTargetKeys(proxy, target); | 733 return CollectOwnJSProxyTargetKeys(proxy, target, keys_conversion); | 
| 730 } | 734 } | 
| 731 // 7. Let trapResultArray be Call(trap, handler, «target»). | 735 // 7. Let trapResultArray be Call(trap, handler, «target»). | 
| 732 Handle<Object> trap_result_array; | 736 Handle<Object> trap_result_array; | 
| 733 Handle<Object> args[] = {target}; | 737 Handle<Object> args[] = {target}; | 
| 734 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 738 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
| 735 isolate_, trap_result_array, | 739 isolate_, trap_result_array, | 
| 736 Execution::Call(isolate_, trap, handler, arraysize(args), args), | 740 Execution::Call(isolate_, trap, handler, arraysize(args), args), | 
| 737 Nothing<bool>()); | 741 Nothing<bool>()); | 
| 738 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, | 742 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, | 
| 739 // «String, Symbol»). | 743 // «String, Symbol»). | 
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 842 DCHECK_GT(unchecked_result_keys_size, 0); | 846 DCHECK_GT(unchecked_result_keys_size, 0); | 
| 843 isolate_->Throw(*isolate_->factory()->NewTypeError( | 847 isolate_->Throw(*isolate_->factory()->NewTypeError( | 
| 844 MessageTemplate::kProxyOwnKeysNonExtensible)); | 848 MessageTemplate::kProxyOwnKeysNonExtensible)); | 
| 845 return Nothing<bool>(); | 849 return Nothing<bool>(); | 
| 846 } | 850 } | 
| 847 // 21. Return trapResult. | 851 // 21. Return trapResult. | 
| 848 return AddKeysFromJSProxy(proxy, trap_result); | 852 return AddKeysFromJSProxy(proxy, trap_result); | 
| 849 } | 853 } | 
| 850 | 854 | 
| 851 Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys( | 855 Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys( | 
| 852 Handle<JSProxy> proxy, Handle<JSReceiver> target) { | 856 Handle<JSProxy> proxy, Handle<JSReceiver> target, | 
| 857 GetKeysConversion keys_conversion) { | |
| 853 // TODO(cbruni): avoid creating another KeyAccumulator | 858 // TODO(cbruni): avoid creating another KeyAccumulator | 
| 854 Handle<FixedArray> keys; | 859 Handle<FixedArray> keys; | 
| 855 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 860 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 
| 856 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>()); | 861 isolate_, keys, | 
| 862 KeyAccumulator::GetKeys(target, KeyCollectionMode::kOwnOnly, filter_, | |
| 
 
Dan Ehrenberg
2016/07/08 22:02:07
It looks like the relevant change here is passing
 
 | |
| 863 keys_conversion, filter_proxy_keys_, is_for_in_), | |
| 864 Nothing<bool>()); | |
| 857 bool prev_filter_proxy_keys_ = filter_proxy_keys_; | 865 bool prev_filter_proxy_keys_ = filter_proxy_keys_; | 
| 858 filter_proxy_keys_ = false; | 866 filter_proxy_keys_ = false; | 
| 859 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); | 867 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); | 
| 860 filter_proxy_keys_ = prev_filter_proxy_keys_; | 868 filter_proxy_keys_ = prev_filter_proxy_keys_; | 
| 861 return result; | 869 return result; | 
| 862 } | 870 } | 
| 863 | 871 | 
| 864 } // namespace internal | 872 } // namespace internal | 
| 865 } // namespace v8 | 873 } // namespace v8 | 
| OLD | NEW |