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 15 matching lines...) Expand all Loading... |
26 for (int i = 0; i < len; i++) { | 26 for (int i = 0; i < len; i++) { |
27 Object* e = array->get(i); | 27 Object* e = array->get(i); |
28 if (!(e->IsName() || e->IsNumber())) return false; | 28 if (!(e->IsName() || e->IsNumber())) return false; |
29 } | 29 } |
30 return true; | 30 return true; |
31 } | 31 } |
32 | 32 |
33 } // namespace | 33 } // namespace |
34 | 34 |
35 MaybeHandle<FixedArray> KeyAccumulator::GetKeys( | 35 MaybeHandle<FixedArray> KeyAccumulator::GetKeys( |
36 Handle<JSReceiver> object, KeyCollectionType type, PropertyFilter filter, | 36 Handle<JSReceiver> object, KeyCollectionMode mode, PropertyFilter filter, |
37 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) { | 37 GetKeysConversion keys_conversion, bool filter_proxy_keys, bool is_for_in) { |
38 USE(ContainsOnlyValidKeys); | 38 USE(ContainsOnlyValidKeys); |
39 Isolate* isolate = object->GetIsolate(); | 39 Isolate* isolate = object->GetIsolate(); |
40 KeyAccumulator accumulator(isolate, type, filter); | 40 KeyAccumulator accumulator(isolate, mode, filter); |
41 accumulator.set_filter_proxy_keys(filter_proxy_keys); | 41 accumulator.set_filter_proxy_keys(filter_proxy_keys); |
42 accumulator.set_is_for_in(is_for_in); | 42 accumulator.set_is_for_in(is_for_in); |
43 MAYBE_RETURN(accumulator.CollectKeys(object, object), | 43 MAYBE_RETURN(accumulator.CollectKeys(object, object), |
44 MaybeHandle<FixedArray>()); | 44 MaybeHandle<FixedArray>()); |
45 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion); | 45 Handle<FixedArray> keys = accumulator.GetKeys(keys_conversion); |
46 DCHECK(ContainsOnlyValidKeys(keys)); | 46 DCHECK(ContainsOnlyValidKeys(keys)); |
47 return keys; | 47 return keys; |
48 } | 48 } |
49 | 49 |
50 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { | 50 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) { |
51 if (keys_.is_null()) { | 51 if (keys_.is_null()) { |
52 return isolate_->factory()->empty_fixed_array(); | 52 return isolate_->factory()->empty_fixed_array(); |
53 } | 53 } |
54 if (type_ == OWN_ONLY && | 54 if (mode_ == KeyCollectionMode::kOwnOnly && |
55 keys_->map() == isolate_->heap()->fixed_array_map()) { | 55 keys_->map() == isolate_->heap()->fixed_array_map()) { |
56 return Handle<FixedArray>::cast(keys_); | 56 return Handle<FixedArray>::cast(keys_); |
57 } | 57 } |
58 return OrderedHashSet::ConvertToKeysArray(keys(), convert); | 58 return OrderedHashSet::ConvertToKeysArray(keys(), convert); |
59 } | 59 } |
60 | 60 |
61 void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { | 61 void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) { |
62 AddKey(handle(key, isolate_), convert); | 62 AddKey(handle(key, isolate_), convert); |
63 } | 63 } |
64 | 64 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
127 | 127 |
128 // Returns "nothing" in case of exception, "true" on success. | 128 // Returns "nothing" in case of exception, "true" on success. |
129 Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy, | 129 Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy, |
130 Handle<FixedArray> keys) { | 130 Handle<FixedArray> keys) { |
131 if (filter_proxy_keys_) { | 131 if (filter_proxy_keys_) { |
132 DCHECK(!is_for_in_); | 132 DCHECK(!is_for_in_); |
133 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 133 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
134 isolate_, keys, FilterProxyKeys(isolate_, proxy, keys, filter_), | 134 isolate_, keys, FilterProxyKeys(isolate_, proxy, keys, filter_), |
135 Nothing<bool>()); | 135 Nothing<bool>()); |
136 } | 136 } |
137 if (type_ == OWN_ONLY && !is_for_in_) { | 137 if (mode_ == KeyCollectionMode::kOwnOnly && !is_for_in_) { |
138 // If we collect only the keys from a JSProxy do not sort or deduplicate it. | 138 // If we collect only the keys from a JSProxy do not sort or deduplicate it. |
139 keys_ = keys; | 139 keys_ = keys; |
140 return Just(true); | 140 return Just(true); |
141 } | 141 } |
142 AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT); | 142 AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT); |
143 return Just(true); | 143 return Just(true); |
144 } | 144 } |
145 | 145 |
146 Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, | 146 Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver, |
147 Handle<JSReceiver> object) { | 147 Handle<JSReceiver> object) { |
148 // Proxies have no hidden prototype and we should not trigger the | 148 // Proxies have no hidden prototype and we should not trigger the |
149 // [[GetPrototypeOf]] trap on the last iteration when using | 149 // [[GetPrototypeOf]] trap on the last iteration when using |
150 // AdvanceFollowingProxies. | 150 // AdvanceFollowingProxies. |
151 if (type_ == OWN_ONLY && object->IsJSProxy()) { | 151 if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) { |
152 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)), | 152 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(object)), |
153 Nothing<bool>()); | 153 Nothing<bool>()); |
154 return Just(true); | 154 return Just(true); |
155 } | 155 } |
156 | 156 |
157 PrototypeIterator::WhereToEnd end = type_ == OWN_ONLY | 157 PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly |
158 ? PrototypeIterator::END_AT_NON_HIDDEN | 158 ? PrototypeIterator::END_AT_NON_HIDDEN |
159 : PrototypeIterator::END_AT_NULL; | 159 : PrototypeIterator::END_AT_NULL; |
160 for (PrototypeIterator iter(isolate_, object, | 160 for (PrototypeIterator iter(isolate_, object, |
161 PrototypeIterator::START_AT_RECEIVER, end); | 161 PrototypeIterator::START_AT_RECEIVER, end); |
162 !iter.IsAtEnd();) { | 162 !iter.IsAtEnd();) { |
163 Handle<JSReceiver> current = | 163 Handle<JSReceiver> current = |
164 PrototypeIterator::GetCurrent<JSReceiver>(iter); | 164 PrototypeIterator::GetCurrent<JSReceiver>(iter); |
165 Maybe<bool> result = Just(false); // Dummy initialization. | 165 Maybe<bool> result = Just(false); // Dummy initialization. |
166 if (current->IsJSProxy()) { | 166 if (current->IsJSProxy()) { |
167 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current)); | 167 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current)); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 } | 202 } |
203 if (object->map()->EnumLength() != 0) return false; | 203 if (object->map()->EnumLength() != 0) return false; |
204 DCHECK(object->IsJSObject()); | 204 DCHECK(object->IsJSObject()); |
205 return !JSObject::cast(object)->HasEnumerableElements(); | 205 return !JSObject::cast(object)->HasEnumerableElements(); |
206 } | 206 } |
207 } // namespace | 207 } // namespace |
208 | 208 |
209 void FastKeyAccumulator::Prepare() { | 209 void FastKeyAccumulator::Prepare() { |
210 DisallowHeapAllocation no_gc; | 210 DisallowHeapAllocation no_gc; |
211 // Directly go for the fast path for OWN_ONLY keys. | 211 // Directly go for the fast path for OWN_ONLY keys. |
212 if (type_ == OWN_ONLY) return; | 212 if (mode_ == KeyCollectionMode::kOwnOnly) return; |
213 // Fully walk the prototype chain and find the last prototype with keys. | 213 // Fully walk the prototype chain and find the last prototype with keys. |
214 is_receiver_simple_enum_ = false; | 214 is_receiver_simple_enum_ = false; |
215 has_empty_prototype_ = true; | 215 has_empty_prototype_ = true; |
216 JSReceiver* first_non_empty_prototype; | 216 JSReceiver* first_non_empty_prototype; |
217 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd(); | 217 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd(); |
218 iter.Advance()) { | 218 iter.Advance()) { |
219 JSReceiver* current = iter.GetCurrent<JSReceiver>(); | 219 JSReceiver* current = iter.GetCurrent<JSReceiver>(); |
220 if (CheckAndInitalizeSimpleEnumCache(current)) continue; | 220 if (CheckAndInitalizeSimpleEnumCache(current)) continue; |
221 has_empty_prototype_ = false; | 221 has_empty_prototype_ = false; |
222 first_non_empty_prototype = current; | 222 first_non_empty_prototype = current; |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { | 365 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(GetKeysConversion convert) { |
366 Handle<FixedArray> keys; | 366 Handle<FixedArray> keys; |
367 if (GetKeysFast(convert).ToHandle(&keys)) { | 367 if (GetKeysFast(convert).ToHandle(&keys)) { |
368 return keys; | 368 return keys; |
369 } | 369 } |
370 return GetKeysSlow(convert); | 370 return GetKeysSlow(convert); |
371 } | 371 } |
372 | 372 |
373 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( | 373 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast( |
374 GetKeysConversion convert) { | 374 GetKeysConversion convert) { |
375 bool own_only = has_empty_prototype_ || type_ == OWN_ONLY; | 375 bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly; |
376 Map* map = receiver_->map(); | 376 Map* map = receiver_->map(); |
377 if (!own_only || !OnlyHasSimpleProperties(map)) { | 377 if (!own_only || !OnlyHasSimpleProperties(map)) { |
378 return MaybeHandle<FixedArray>(); | 378 return MaybeHandle<FixedArray>(); |
379 } | 379 } |
380 | 380 |
381 // From this point on we are certiain to only collect own keys. | 381 // From this point on we are certiain to only collect own keys. |
382 DCHECK(receiver_->IsJSObject()); | 382 DCHECK(receiver_->IsJSObject()); |
383 Handle<JSObject> object = Handle<JSObject>::cast(receiver_); | 383 Handle<JSObject> object = Handle<JSObject>::cast(receiver_); |
384 | 384 |
385 // Do not try to use the enum-cache for dict-mode objects. | 385 // Do not try to use the enum-cache for dict-mode objects. |
(...skipping 15 matching lines...) Expand all Loading... |
401 return keys; | 401 return keys; |
402 } | 402 } |
403 } | 403 } |
404 // The properties-only case failed because there were probably elements on the | 404 // The properties-only case failed because there were probably elements on the |
405 // receiver. | 405 // receiver. |
406 return GetOwnKeysWithElements<true>(isolate_, object, convert); | 406 return GetOwnKeysWithElements<true>(isolate_, object, convert); |
407 } | 407 } |
408 | 408 |
409 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( | 409 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow( |
410 GetKeysConversion convert) { | 410 GetKeysConversion convert) { |
411 return KeyAccumulator::GetKeys(receiver_, type_, filter_, KEEP_NUMBERS, | 411 return KeyAccumulator::GetKeys(receiver_, mode_, filter_, |
| 412 GetKeysConversion::kKeepNumbers, |
412 filter_proxy_keys_, is_for_in_); | 413 filter_proxy_keys_, is_for_in_); |
413 } | 414 } |
414 | 415 |
415 namespace { | 416 namespace { |
416 | 417 |
417 enum IndexedOrNamed { kIndexed, kNamed }; | 418 enum IndexedOrNamed { kIndexed, kNamed }; |
418 | 419 |
419 // Returns |true| on success, |nothing| on exception. | 420 // Returns |true| on success, |nothing| on exception. |
420 template <class Callback, IndexedOrNamed type> | 421 template <class Callback, IndexedOrNamed type> |
421 Maybe<bool> GetKeysFromInterceptor(Handle<JSReceiver> receiver, | 422 Maybe<bool> GetKeysFromInterceptor(Handle<JSReceiver> receiver, |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
529 | 530 |
530 // Returns |true| on success, |false| if prototype walking should be stopped, | 531 // Returns |true| on success, |false| if prototype walking should be stopped, |
531 // |nothing| if an exception was thrown. | 532 // |nothing| if an exception was thrown. |
532 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, | 533 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver, |
533 Handle<JSObject> object) { | 534 Handle<JSObject> object) { |
534 // Check access rights if required. | 535 // Check access rights if required. |
535 if (object->IsAccessCheckNeeded() && | 536 if (object->IsAccessCheckNeeded() && |
536 !isolate_->MayAccess(handle(isolate_->context()), object)) { | 537 !isolate_->MayAccess(handle(isolate_->context()), object)) { |
537 // The cross-origin spec says that [[Enumerate]] shall return an empty | 538 // The cross-origin spec says that [[Enumerate]] shall return an empty |
538 // iterator when it doesn't have access... | 539 // iterator when it doesn't have access... |
539 if (type_ == INCLUDE_PROTOS) { | 540 if (mode_ == KeyCollectionMode::kIncludePrototypes) { |
540 return Just(false); | 541 return Just(false); |
541 } | 542 } |
542 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. | 543 // ...whereas [[OwnPropertyKeys]] shall return whitelisted properties. |
543 DCHECK_EQ(OWN_ONLY, type_); | 544 DCHECK(KeyCollectionMode::kOwnOnly == mode_); |
544 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); | 545 filter_ = static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ); |
545 } | 546 } |
546 MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>()); | 547 MAYBE_RETURN(CollectOwnElementIndices(receiver, object), Nothing<bool>()); |
547 MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>()); | 548 MAYBE_RETURN(CollectOwnPropertyNames(receiver, object), Nothing<bool>()); |
548 return Just(true); | 549 return Just(true); |
549 } | 550 } |
550 | 551 |
551 // static | 552 // static |
552 Handle<FixedArray> KeyAccumulator::GetEnumPropertyKeys( | 553 Handle<FixedArray> KeyAccumulator::GetEnumPropertyKeys( |
553 Isolate* isolate, Handle<JSObject> object) { | 554 Isolate* isolate, Handle<JSObject> object) { |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
729 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>()); | 730 isolate_, keys, JSReceiver::OwnPropertyKeys(target), Nothing<bool>()); |
730 bool prev_filter_proxy_keys_ = filter_proxy_keys_; | 731 bool prev_filter_proxy_keys_ = filter_proxy_keys_; |
731 filter_proxy_keys_ = false; | 732 filter_proxy_keys_ = false; |
732 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); | 733 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys); |
733 filter_proxy_keys_ = prev_filter_proxy_keys_; | 734 filter_proxy_keys_ = prev_filter_proxy_keys_; |
734 return result; | 735 return result; |
735 } | 736 } |
736 | 737 |
737 } // namespace internal | 738 } // namespace internal |
738 } // namespace v8 | 739 } // namespace v8 |
OLD | NEW |