7 #include "src/api-arguments-inl.h" 8 #include "src/elements-inl.h" 9 #include "src/handles-inl.h" 10 #include "src/heap/factory.h" 11 #include "src/identity-map.h" 12 #include "src/isolate-inl.h" 13 #include "src/objects-inl.h" 14 #include "src/objects/api-callbacks.h" 15 #include "src/objects/hash-table-inl.h" 16 #include "src/objects/module-inl.h" 17 #include "src/property-descriptor.h" 18 #include "src/prototype.h" 25 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
26 int len = array->length();
27 for (
int i = 0;
i < len;
i++) {
28 Object* e = array->get(
i);
29 if (!(e->IsName() || e->IsNumber()))
return false;
37 MaybeHandle<FixedArray> KeyAccumulator::GetKeys(
39 GetKeysConversion keys_conversion,
bool is_for_in,
bool skip_indices) {
40 Isolate* isolate =
object->GetIsolate();
41 FastKeyAccumulator accumulator(isolate,
object, mode, filter, is_for_in,
43 return accumulator.GetKeys(keys_conversion);
46 Handle<FixedArray> KeyAccumulator::GetKeys(GetKeysConversion convert) {
47 if (keys_.is_null()) {
48 return isolate_->factory()->empty_fixed_array();
50 if (mode_ == KeyCollectionMode::kOwnOnly &&
51 keys_->map() == ReadOnlyRoots(isolate_).fixed_array_map()) {
52 return Handle<FixedArray>::cast(keys_);
54 USE(ContainsOnlyValidKeys);
55 Handle<FixedArray> result =
56 OrderedHashSet::ConvertToKeysArray(isolate(), keys(), convert);
57 DCHECK(ContainsOnlyValidKeys(result));
61 Handle<OrderedHashSet> KeyAccumulator::keys() {
62 return Handle<OrderedHashSet>::cast(keys_);
65 void KeyAccumulator::AddKey(Object* key, AddKeyConversion convert) {
66 AddKey(handle(key, isolate_), convert);
69 void KeyAccumulator::AddKey(Handle<Object> key, AddKeyConversion convert) {
70 if (key->IsSymbol()) {
71 if (filter_ & SKIP_SYMBOLS)
return;
72 if (Handle<Symbol>::cast(key)->is_private())
return;
73 }
else if (filter_ & SKIP_STRINGS) {
76 if (IsShadowed(key))
return;
77 if (keys_.is_null()) {
80 Handle<FixedArray>(OrderedHashSet::Allocate(isolate_, 16).location());
83 if (convert == CONVERT_TO_ARRAY_INDEX && key->IsString() &&
84 Handle<String>::cast(key)->AsArrayIndex(&index)) {
85 key = isolate_->factory()->NewNumberFromUint(index);
87 Handle<OrderedHashSet> new_set = OrderedHashSet::Add(isolate(), keys(), key);
88 if (*new_set != *keys_) {
92 keys_->set(OrderedHashSet::kNextTableIndex, Smi::kZero);
94 keys_ = Handle<FixedArray>(new_set.location());
98 void KeyAccumulator::AddKeys(Handle<FixedArray> array,
99 AddKeyConversion convert) {
100 int add_length = array->length();
101 for (
int i = 0;
i < add_length;
i++) {
102 Handle<Object> current(array->get(
i), isolate_);
103 AddKey(current, convert);
107 void KeyAccumulator::AddKeys(Handle<JSObject> array_like,
108 AddKeyConversion convert) {
109 DCHECK(array_like->IsJSArray() || array_like->HasSloppyArgumentsElements());
110 ElementsAccessor* accessor = array_like->GetElementsAccessor();
111 accessor->AddElementsToKeyAccumulator(array_like,
this, convert);
114 MaybeHandle<FixedArray> FilterProxyKeys(KeyAccumulator* accumulator,
115 Handle<JSProxy> owner,
116 Handle<FixedArray> keys,
118 if (filter == ALL_PROPERTIES) {
122 Isolate* isolate = accumulator->isolate();
123 int store_position = 0;
124 for (
int i = 0;
i < keys->length(); ++
i) {
125 Handle<Name> key(Name::cast(keys->get(
i)), isolate);
126 if (key->FilterKey(filter))
continue;
127 if (filter & ONLY_ENUMERABLE) {
128 PropertyDescriptor desc;
130 JSProxy::GetOwnPropertyDescriptor(isolate, owner, key, &desc);
131 MAYBE_RETURN(found, MaybeHandle<FixedArray>());
132 if (!found.FromJust())
continue;
133 if (!desc.enumerable()) {
134 accumulator->AddShadowingKey(key);
139 if (store_position !=
i) {
140 keys->set(store_position, *key);
144 return FixedArray::ShrinkOrEmpty(isolate, keys, store_position);
148 Maybe<bool> KeyAccumulator::AddKeysFromJSProxy(Handle<JSProxy> proxy,
149 Handle<FixedArray> keys) {
152 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
153 isolate_, keys, FilterProxyKeys(
this, proxy, keys, filter_),
155 if (mode_ == KeyCollectionMode::kOwnOnly) {
161 AddKeys(keys, is_for_in_ ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
165 Maybe<bool> KeyAccumulator::CollectKeys(Handle<JSReceiver> receiver,
166 Handle<JSReceiver>
object) {
170 if (mode_ == KeyCollectionMode::kOwnOnly && object->IsJSProxy()) {
171 MAYBE_RETURN(CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(
object)),
176 PrototypeIterator::WhereToEnd end = mode_ == KeyCollectionMode::kOwnOnly
177 ? PrototypeIterator::END_AT_NON_HIDDEN
178 : PrototypeIterator::END_AT_NULL;
179 for (PrototypeIterator iter(isolate_,
object, kStartAtReceiver, end);
183 if (HasShadowingKeys()) skip_shadow_check_ =
false;
184 Handle<JSReceiver> current =
185 PrototypeIterator::GetCurrent<JSReceiver>(iter);
186 Maybe<bool> result = Just(
false);
187 if (current->IsJSProxy()) {
188 result = CollectOwnJSProxyKeys(receiver, Handle<JSProxy>::cast(current));
190 DCHECK(current->IsJSObject());
191 result = CollectOwnKeys(receiver, Handle<JSObject>::cast(current));
193 MAYBE_RETURN(result, Nothing<bool>());
194 if (!result.FromJust())
break;
197 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
198 return Nothing<bool>();
200 if (!last_non_empty_prototype_.is_null() &&
201 *last_non_empty_prototype_ == *current) {
208 bool KeyAccumulator::HasShadowingKeys() {
return !shadowing_keys_.is_null(); }
210 bool KeyAccumulator::IsShadowed(Handle<Object> key) {
211 if (!HasShadowingKeys() || skip_shadow_check_)
return false;
212 return shadowing_keys_->Has(isolate_, key);
215 void KeyAccumulator::AddShadowingKey(Object* key) {
216 if (mode_ == KeyCollectionMode::kOwnOnly)
return;
217 AddShadowingKey(handle(key, isolate_));
219 void KeyAccumulator::AddShadowingKey(Handle<Object> key) {
220 if (mode_ == KeyCollectionMode::kOwnOnly)
return;
221 if (shadowing_keys_.is_null()) {
222 shadowing_keys_ = ObjectHashSet::New(isolate_, 16);
224 shadowing_keys_ = ObjectHashSet::Add(isolate(), shadowing_keys_, key);
229 void TrySettingEmptyEnumCache(JSReceiver*
object) {
230 Map map =
object->map();
231 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
232 if (!map->OnlyHasSimpleProperties())
return;
233 if (map->IsJSProxyMap())
return;
234 if (map->NumberOfEnumerableProperties() > 0)
return;
235 DCHECK(object->IsJSObject());
236 map->SetEnumLength(0);
239 bool CheckAndInitalizeEmptyEnumCache(JSReceiver*
object) {
240 if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) {
241 TrySettingEmptyEnumCache(
object);
243 if (object->map()->EnumLength() != 0)
return false;
244 DCHECK(object->IsJSObject());
245 return !JSObject::cast(
object)->HasEnumerableElements();
249 void FastKeyAccumulator::Prepare() {
250 DisallowHeapAllocation no_gc;
252 if (mode_ == KeyCollectionMode::kOwnOnly)
return;
254 is_receiver_simple_enum_ =
false;
255 has_empty_prototype_ =
true;
256 JSReceiver* last_prototype =
nullptr;
257 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
259 JSReceiver* current = iter.GetCurrent<JSReceiver>();
260 bool has_no_properties = CheckAndInitalizeEmptyEnumCache(current);
261 if (has_no_properties)
continue;
262 last_prototype = current;
263 has_empty_prototype_ =
false;
265 if (has_empty_prototype_) {
266 is_receiver_simple_enum_ =
267 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
268 !JSObject::cast(*receiver_)->HasEnumerableElements();
269 }
else if (last_prototype !=
nullptr) {
270 last_non_empty_prototype_ = handle(last_prototype, isolate_);
276 Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
277 Handle<FixedArray> array,
int length) {
278 DCHECK_LE(length, array->length());
279 if (array->length() == length)
return array;
280 return isolate->factory()->CopyFixedArrayUpTo(array, length);
285 Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
286 Handle<JSObject>
object) {
287 Handle<Map> map(object->map(), isolate);
288 Handle<FixedArray> keys(map->instance_descriptors()->enum_cache()->keys(),
293 int enum_length = map->EnumLength();
294 if (enum_length != kInvalidEnumCacheSentinel) {
295 DCHECK(map->OnlyHasSimpleProperties());
296 DCHECK_LE(enum_length, keys->length());
297 DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
298 isolate->counters()->enum_cache_hits()->Increment();
299 return ReduceFixedArrayTo(isolate, keys, enum_length);
303 enum_length = map->NumberOfEnumerableProperties();
307 if (enum_length <= keys->length()) {
308 if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
309 isolate->counters()->enum_cache_hits()->Increment();
310 return ReduceFixedArrayTo(isolate, keys, enum_length);
313 Handle<DescriptorArray> descriptors =
314 Handle<DescriptorArray>(map->instance_descriptors(), isolate);
315 isolate->counters()->enum_cache_misses()->Increment();
316 int nod = map->NumberOfOwnDescriptors();
320 bool fields_only =
true;
321 keys = isolate->factory()->NewFixedArray(enum_length);
322 for (
int i = 0;
i < nod;
i++) {
323 DisallowHeapAllocation no_gc;
324 PropertyDetails details = descriptors->GetDetails(
i);
325 if (details.IsDontEnum())
continue;
326 Object* key = descriptors->GetKey(
i);
327 if (key->IsSymbol())
continue;
328 keys->set(index, key);
329 if (details.location() != kField) fields_only =
false;
332 DCHECK_EQ(index, keys->length());
335 Handle<FixedArray> indices = isolate->factory()->empty_fixed_array();
337 indices = isolate->factory()->NewFixedArray(enum_length);
339 for (
int i = 0;
i < nod;
i++) {
340 DisallowHeapAllocation no_gc;
341 PropertyDetails details = descriptors->GetDetails(
i);
342 if (details.IsDontEnum())
continue;
343 Object* key = descriptors->GetKey(
i);
344 if (key->IsSymbol())
continue;
345 DCHECK_EQ(kData, details.kind());
346 DCHECK_EQ(kField, details.location());
347 FieldIndex field_index = FieldIndex::ForDescriptor(*map,
i);
348 indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
351 DCHECK_EQ(index, indices->length());
354 DescriptorArray::InitializeOrChangeEnumCache(descriptors, isolate, keys,
356 if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
361 template <
bool fast_properties>
362 MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
363 Handle<JSObject>
object,
364 GetKeysConversion convert,
366 Handle<FixedArray> keys;
367 ElementsAccessor* accessor =
object->GetElementsAccessor();
368 if (fast_properties) {
369 keys = GetFastEnumPropertyKeys(isolate,
object);
372 keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate,
object);
375 MaybeHandle<FixedArray> result;
380 accessor->PrependElementIndices(
object, keys, convert, ONLY_ENUMERABLE);
383 if (FLAG_trace_for_in_enumerate) {
384 PrintF(
"| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n",
385 keys->length(), result.ToHandleChecked()->length() - keys->length());
392 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeys(
393 GetKeysConversion keys_conversion) {
394 if (filter_ == ENUMERABLE_STRINGS) {
395 Handle<FixedArray> keys;
396 if (GetKeysFast(keys_conversion).ToHandle(&keys)) {
399 if (isolate_->has_pending_exception())
return MaybeHandle<FixedArray>();
402 return GetKeysSlow(keys_conversion);
405 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysFast(
406 GetKeysConversion keys_conversion) {
407 bool own_only = has_empty_prototype_ || mode_ == KeyCollectionMode::kOwnOnly;
408 Map map = receiver_->map();
409 if (!own_only || map->IsCustomElementsReceiverMap()) {
410 return MaybeHandle<FixedArray>();
414 DCHECK(receiver_->IsJSObject());
415 Handle<JSObject>
object = Handle<JSObject>::cast(receiver_);
418 if (map->is_dictionary_map()) {
419 return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion,
422 int enum_length = receiver_->map()->EnumLength();
423 if (enum_length == kInvalidEnumCacheSentinel) {
424 Handle<FixedArray> keys;
426 if (GetOwnKeysWithUninitializedEnumCache().ToHandle(&keys)) {
427 if (FLAG_trace_for_in_enumerate) {
428 PrintF(
"| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n",
431 is_receiver_simple_enum_ =
432 object->map()->EnumLength() != kInvalidEnumCacheSentinel;
438 return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion,
442 MaybeHandle<FixedArray>
443 FastKeyAccumulator::GetOwnKeysWithUninitializedEnumCache() {
444 Handle<JSObject>
object = Handle<JSObject>::cast(receiver_);
446 Map map =
object->map();
447 if (object->elements()->length() != 0) {
449 return MaybeHandle<FixedArray>();
451 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
452 if (number_of_own_descriptors == 0) {
453 map->SetEnumLength(0);
454 return isolate_->factory()->empty_fixed_array();
458 Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_,
object);
459 if (is_for_in_)
return keys;
461 return isolate_->factory()->CopyFixedArray(keys);
464 MaybeHandle<FixedArray> FastKeyAccumulator::GetKeysSlow(
465 GetKeysConversion keys_conversion) {
466 KeyAccumulator accumulator(isolate_, mode_, filter_);
467 accumulator.set_is_for_in(is_for_in_);
468 accumulator.set_skip_indices(skip_indices_);
469 accumulator.set_last_non_empty_prototype(last_non_empty_prototype_);
471 MAYBE_RETURN(accumulator.CollectKeys(receiver_, receiver_),
472 MaybeHandle<FixedArray>());
473 return accumulator.GetKeys(keys_conversion);
478 enum IndexedOrNamed { kIndexed, kNamed };
480 void FilterForEnumerableProperties(Handle<JSReceiver> receiver,
481 Handle<JSObject>
object,
482 Handle<InterceptorInfo> interceptor,
483 KeyAccumulator* accumulator,
484 Handle<JSObject> result,
485 IndexedOrNamed type) {
486 DCHECK(result->IsJSArray() || result->HasSloppyArgumentsElements());
487 ElementsAccessor* accessor = result->GetElementsAccessor();
489 uint32_t length = accessor->GetCapacity(*result, result->elements());
491 if (!accessor->HasEntry(*result,
i))
continue;
494 PropertyCallbackArguments args(accumulator->isolate(), interceptor->data(),
495 *receiver, *object, kDontThrow);
497 Handle<Object> element = accessor->Get(result,
i);
498 Handle<Object> attributes;
499 if (type == kIndexed) {
501 CHECK(element->ToUint32(&number));
502 attributes = args.CallIndexedQuery(interceptor, number);
504 CHECK(element->IsName());
506 args.CallNamedQuery(interceptor, Handle<Name>::cast(element));
509 if (!attributes.is_null()) {
511 CHECK(attributes->ToInt32(&value));
512 if ((value & DONT_ENUM) == 0) {
513 accumulator->AddKey(element, DO_NOT_CONVERT);
520 Maybe<bool> CollectInterceptorKeysInternal(Handle<JSReceiver> receiver,
521 Handle<JSObject>
object,
522 Handle<InterceptorInfo> interceptor,
523 KeyAccumulator* accumulator,
524 IndexedOrNamed type) {
525 Isolate* isolate = accumulator->isolate();
526 PropertyCallbackArguments enum_args(isolate, interceptor->data(), *receiver,
527 *object, kDontThrow);
529 Handle<JSObject> result;
530 if (!interceptor->enumerator()->IsUndefined(isolate)) {
531 if (type == kIndexed) {
532 result = enum_args.CallIndexedEnumerator(interceptor);
534 DCHECK_EQ(type, kNamed);
535 result = enum_args.CallNamedEnumerator(interceptor);
538 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>());
539 if (result.is_null())
return Just(
true);
541 if ((accumulator->filter() & ONLY_ENUMERABLE) &&
542 !interceptor->query()->IsUndefined(isolate)) {
543 FilterForEnumerableProperties(receiver,
object, interceptor, accumulator,
546 accumulator->AddKeys(
547 result, type == kIndexed ? CONVERT_TO_ARRAY_INDEX : DO_NOT_CONVERT);
552 Maybe<bool> CollectInterceptorKeys(Handle<JSReceiver> receiver,
553 Handle<JSObject>
object,
554 KeyAccumulator* accumulator,
555 IndexedOrNamed type) {
556 Isolate* isolate = accumulator->isolate();
557 if (type == kIndexed) {
558 if (!object->HasIndexedInterceptor())
return Just(
true);
560 if (!object->HasNamedInterceptor())
return Just(
true);
562 Handle<InterceptorInfo> interceptor(type == kIndexed
563 ? object->GetIndexedInterceptor()
564 :
object->GetNamedInterceptor(),
566 if ((accumulator->filter() & ONLY_ALL_CAN_READ) &&
567 !interceptor->all_can_read()) {
570 return CollectInterceptorKeysInternal(receiver,
object, interceptor,
576 Maybe<bool> KeyAccumulator::CollectOwnElementIndices(
577 Handle<JSReceiver> receiver, Handle<JSObject>
object) {
578 if (filter_ & SKIP_STRINGS || skip_indices_)
return Just(
true);
580 ElementsAccessor* accessor =
object->GetElementsAccessor();
581 accessor->CollectElementIndices(
object,
this);
583 return CollectInterceptorKeys(receiver,
object,
this, kIndexed);
588 template <
bool skip_symbols>
589 int CollectOwnPropertyNamesInternal(Handle<JSObject>
object,
590 KeyAccumulator* keys,
591 Handle<DescriptorArray> descs,
592 int start_index,
int limit) {
593 int first_skipped = -1;
596 for (
int i = start_index;
i < limit;
i++) {
597 bool is_shadowing_key =
false;
598 PropertyDetails details = descs->GetDetails(
i);
600 if ((details.attributes() & filter) != 0) {
601 if (mode == KeyCollectionMode::kIncludePrototypes) {
602 is_shadowing_key =
true;
608 if (filter & ONLY_ALL_CAN_READ) {
609 if (details.kind() != kAccessor)
continue;
610 Object* accessors = descs->GetStrongValue(
i);
611 if (!accessors->IsAccessorInfo())
continue;
612 if (!AccessorInfo::cast(accessors)->all_can_read())
continue;
615 Name key = descs->GetKey(
i);
616 if (skip_symbols == key->IsSymbol()) {
617 if (first_skipped == -1) first_skipped =
i;
620 if (key->FilterKey(keys->filter()))
continue;
622 if (is_shadowing_key) {
623 keys->AddShadowingKey(key);
625 keys->AddKey(key, DO_NOT_CONVERT);
628 return first_skipped;
632 Handle<FixedArray> GetOwnEnumPropertyDictionaryKeys(Isolate* isolate,
634 KeyAccumulator* accumulator,
635 Handle<JSObject>
object,
637 Handle<T> dictionary(raw_dictionary, isolate);
638 if (dictionary->NumberOfElements() == 0) {
639 return isolate->factory()->empty_fixed_array();
641 int length = dictionary->NumberOfEnumerableProperties();
642 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
643 T::CopyEnumKeysTo(isolate, dictionary, storage, mode, accumulator);
648 Maybe<bool> KeyAccumulator::CollectOwnPropertyNames(Handle<JSReceiver> receiver,
649 Handle<JSObject>
object) {
650 if (filter_ == ENUMERABLE_STRINGS) {
651 Handle<FixedArray> enum_keys;
652 if (object->HasFastProperties()) {
653 enum_keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate_,
object);
656 Map map =
object->map();
657 int nof_descriptors = map->NumberOfOwnDescriptors();
658 if (enum_keys->length() != nof_descriptors) {
659 Handle<DescriptorArray> descs =
660 Handle<DescriptorArray>(map->instance_descriptors(), isolate_);
661 for (
int i = 0;
i < nof_descriptors;
i++) {
662 PropertyDetails details = descs->GetDetails(
i);
663 if (!details.IsDontEnum())
continue;
664 Object* key = descs->GetKey(
i);
665 this->AddShadowingKey(key);
668 }
else if (object->IsJSGlobalObject()) {
669 enum_keys = GetOwnEnumPropertyDictionaryKeys(
670 isolate_, mode_,
this,
object,
671 JSGlobalObject::cast(*object)->global_dictionary());
673 enum_keys = GetOwnEnumPropertyDictionaryKeys(
674 isolate_, mode_,
this,
object, object->property_dictionary());
676 if (object->IsJSModuleNamespace()) {
679 for (
int i = 0, n = enum_keys->length();
i < n; ++
i) {
680 Handle<String> key(String::cast(enum_keys->get(
i)), isolate_);
681 if (Handle<JSModuleNamespace>::cast(
object)
682 ->GetExport(isolate(), key)
684 return Nothing<bool>();
688 AddKeys(enum_keys, DO_NOT_CONVERT);
690 if (object->HasFastProperties()) {
691 int limit =
object->map()->NumberOfOwnDescriptors();
692 Handle<DescriptorArray> descs(object->map()->instance_descriptors(),
696 CollectOwnPropertyNamesInternal<true>(object,
this, descs, 0, limit);
698 if (first_symbol != -1) {
699 CollectOwnPropertyNamesInternal<false>(object,
this, descs,
700 first_symbol, limit);
702 }
else if (object->IsJSGlobalObject()) {
703 GlobalDictionary::CollectKeysTo(
704 handle(JSGlobalObject::cast(*object)->global_dictionary(), isolate_),
707 NameDictionary::CollectKeysTo(
708 handle(object->property_dictionary(), isolate_),
this);
712 return CollectInterceptorKeys(receiver,
object,
this, kNamed);
715 Maybe<bool> KeyAccumulator::CollectAccessCheckInterceptorKeys(
716 Handle<AccessCheckInfo> access_check_info, Handle<JSReceiver> receiver,
717 Handle<JSObject>
object) {
718 if (!skip_indices_) {
719 MAYBE_RETURN((CollectInterceptorKeysInternal(
721 handle(InterceptorInfo::cast(
722 access_check_info->indexed_interceptor()),
728 (CollectInterceptorKeysInternal(
730 handle(InterceptorInfo::cast(access_check_info->named_interceptor()),
739 Maybe<bool> KeyAccumulator::CollectOwnKeys(Handle<JSReceiver> receiver,
740 Handle<JSObject>
object) {
742 if (object->IsAccessCheckNeeded() &&
743 !isolate_->MayAccess(handle(isolate_->context(), isolate_),
object)) {
746 if (mode_ == KeyCollectionMode::kIncludePrototypes) {
750 DCHECK_EQ(KeyCollectionMode::kOwnOnly, mode_);
751 Handle<AccessCheckInfo> access_check_info;
753 DisallowHeapAllocation no_gc;
754 AccessCheckInfo* maybe_info = AccessCheckInfo::Get(isolate_,
object);
755 if (maybe_info) access_check_info = handle(maybe_info, isolate_);
758 if (!access_check_info.is_null() &&
759 access_check_info->named_interceptor()) {
760 MAYBE_RETURN(CollectAccessCheckInterceptorKeys(access_check_info,
765 filter_ =
static_cast<PropertyFilter>(filter_ | ONLY_ALL_CAN_READ);
767 MAYBE_RETURN(CollectOwnElementIndices(receiver,
object), Nothing<bool>());
768 MAYBE_RETURN(CollectOwnPropertyNames(receiver,
object), Nothing<bool>());
773 Handle<FixedArray> KeyAccumulator::GetOwnEnumPropertyKeys(
774 Isolate* isolate, Handle<JSObject>
object) {
775 if (object->HasFastProperties()) {
776 return GetFastEnumPropertyKeys(isolate,
object);
777 }
else if (object->IsJSGlobalObject()) {
778 return GetOwnEnumPropertyDictionaryKeys(
779 isolate, KeyCollectionMode::kOwnOnly,
nullptr,
object,
780 JSGlobalObject::cast(*object)->global_dictionary());
782 return GetOwnEnumPropertyDictionaryKeys(
783 isolate, KeyCollectionMode::kOwnOnly,
nullptr,
object,
784 object->property_dictionary());
790 class NameComparator {
792 explicit NameComparator(Isolate* isolate) : isolate_(isolate) {}
795 const Handle<Name>& key2)
const {
796 return Name::Equals(isolate_, key1, key2);
807 Maybe<bool> KeyAccumulator::CollectOwnJSProxyKeys(Handle<JSReceiver> receiver,
808 Handle<JSProxy> proxy) {
809 STACK_CHECK(isolate_, Nothing<bool>());
811 Handle<Object> handler(proxy->handler(), isolate_);
814 if (proxy->IsRevoked()) {
815 isolate_->Throw(*isolate_->factory()->NewTypeError(
816 MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string()));
817 return Nothing<bool>();
820 Handle<JSReceiver> target(JSReceiver::cast(proxy->target()), isolate_);
823 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
824 isolate_, trap, Object::GetMethod(Handle<JSReceiver>::cast(handler),
825 isolate_->factory()->ownKeys_string()),
828 if (trap->IsUndefined(isolate_)) {
830 return CollectOwnJSProxyTargetKeys(proxy, target);
833 Handle<Object> trap_result_array;
834 Handle<Object> args[] = {target};
835 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
836 isolate_, trap_result_array,
837 Execution::Call(isolate_, trap, handler, arraysize(args), args),
841 Handle<FixedArray> trap_result;
842 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
843 isolate_, trap_result,
844 Object::CreateListFromArrayLike(isolate_, trap_result_array,
845 ElementTypes::kStringAndSymbol),
848 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(target);
849 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
850 bool extensible_target = maybe_extensible.FromJust();
852 Handle<FixedArray> target_keys;
853 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, target_keys,
854 JSReceiver::OwnPropertyKeys(target),
859 Handle<FixedArray> target_configurable_keys = target_keys;
861 Handle<FixedArray> target_nonconfigurable_keys =
862 isolate_->factory()->NewFixedArray(target_keys->length());
863 int nonconfigurable_keys_length = 0;
865 for (
int i = 0;
i < target_keys->length(); ++
i) {
867 PropertyDescriptor desc;
868 Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor(
869 isolate_, target, handle(target_keys->get(
i), isolate_), &desc);
870 MAYBE_RETURN(found, Nothing<bool>());
872 if (found.FromJust() && !desc.configurable()) {
874 target_nonconfigurable_keys->set(nonconfigurable_keys_length,
875 target_keys->get(
i));
876 nonconfigurable_keys_length++;
878 target_keys->set(
i, Smi::kZero);
887 if (extensible_target && nonconfigurable_keys_length == 0) {
889 return AddKeysFromJSProxy(proxy, trap_result);
892 Zone set_zone(isolate_->allocator(), ZONE_NAME);
893 ZoneAllocationPolicy alloc(&set_zone);
894 const int kPresent = 1;
896 base::TemplateHashMapImpl<Handle<Name>,
int, NameComparator,
897 ZoneAllocationPolicy>
898 unchecked_result_keys(ZoneHashMap::kDefaultHashMapCapacity,
899 NameComparator(isolate_), alloc);
900 int unchecked_result_keys_size = 0;
901 for (
int i = 0;
i < trap_result->length(); ++
i) {
902 Handle<Name> key(Name::cast(trap_result->get(
i)), isolate_);
903 auto entry = unchecked_result_keys.LookupOrInsert(key, key->Hash(), alloc);
904 if (entry->value != kPresent) {
905 entry->value = kPresent;
906 unchecked_result_keys_size++;
910 for (
int i = 0;
i < nonconfigurable_keys_length; ++
i) {
911 Object* raw_key = target_nonconfigurable_keys->get(
i);
912 Handle<Name> key(Name::cast(raw_key), isolate_);
915 auto found = unchecked_result_keys.Lookup(key, key->Hash());
916 if (found ==
nullptr || found->value == kGone) {
917 isolate_->Throw(*isolate_->factory()->NewTypeError(
918 MessageTemplate::kProxyOwnKeysMissing, key));
919 return Nothing<bool>();
922 found->value = kGone;
923 unchecked_result_keys_size--;
926 if (extensible_target) {
927 return AddKeysFromJSProxy(proxy, trap_result);
930 for (
int i = 0;
i < target_configurable_keys->length(); ++
i) {
931 Object* raw_key = target_configurable_keys->get(
i);
932 if (raw_key->IsSmi())
continue;
933 Handle<Name> key(Name::cast(raw_key), isolate_);
936 auto found = unchecked_result_keys.Lookup(key, key->Hash());
937 if (found ==
nullptr || found->value == kGone) {
938 isolate_->Throw(*isolate_->factory()->NewTypeError(
939 MessageTemplate::kProxyOwnKeysMissing, key));
940 return Nothing<bool>();
943 found->value = kGone;
944 unchecked_result_keys_size--;
947 if (unchecked_result_keys_size != 0) {
948 DCHECK_GT(unchecked_result_keys_size, 0);
949 isolate_->Throw(*isolate_->factory()->NewTypeError(
950 MessageTemplate::kProxyOwnKeysNonExtensible));
951 return Nothing<bool>();
954 return AddKeysFromJSProxy(proxy, trap_result);
957 Maybe<bool> KeyAccumulator::CollectOwnJSProxyTargetKeys(
958 Handle<JSProxy> proxy, Handle<JSReceiver> target) {
960 Handle<FixedArray> keys;
961 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
963 KeyAccumulator::GetKeys(
964 target, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES,
965 GetKeysConversion::kConvertToString, is_for_in_, skip_indices_),
967 Maybe<bool> result = AddKeysFromJSProxy(proxy, keys);