v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
keys.cc
Go to the documentation of this file.
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
3// found in the LICENSE file.
4
5#include "src/objects/keys.h"
6
7#include <optional>
8
10#include "src/api/api.h"
12#include "src/common/globals.h"
15#include "src/heap/factory.h"
29
30namespace v8::internal {
31
32#define RETURN_NOTHING_IF_NOT_SUCCESSFUL(call) \
33 do { \
34 if (!(call)) return Nothing<bool>(); \
35 } while (false)
36
37#define RETURN_FAILURE_IF_NOT_SUCCESSFUL(call) \
38 do { \
39 ExceptionStatus status_enum_result = (call); \
40 if (!status_enum_result) return status_enum_result; \
41 } while (false)
42
43namespace {
44
45static bool ContainsOnlyValidKeys(DirectHandle<FixedArray> array) {
46 int len = array->length();
47 for (int i = 0; i < len; i++) {
48 Tagged<Object> e = array->get(i);
49 if (!(IsName(e) || IsNumber(e))) return false;
50 }
51 return true;
52}
53
54static int AddKey(Tagged<Object> key, DirectHandle<FixedArray> combined_keys,
55 DirectHandle<DescriptorArray> descs, int nof_descriptors,
56 int target) {
57 for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
58 if (descs->GetKey(i) == key) return 0;
59 }
60 combined_keys->set(target, key);
61 return 1;
62}
63
64static Handle<FixedArray> CombineKeys(Isolate* isolate,
65 Handle<FixedArray> own_keys,
66 Handle<FixedArray> prototype_chain_keys,
67 DirectHandle<JSReceiver> receiver,
68 bool may_have_elements) {
69 int prototype_chain_keys_length = prototype_chain_keys->length();
70 if (prototype_chain_keys_length == 0) return own_keys;
71
72 Tagged<Map> map = receiver->map();
73 int nof_descriptors = map->NumberOfOwnDescriptors();
74 if (nof_descriptors == 0 && !may_have_elements) return prototype_chain_keys;
75
76 DirectHandle<DescriptorArray> descs(map->instance_descriptors(isolate),
77 isolate);
78 int own_keys_length = own_keys.is_null() ? 0 : own_keys->length();
79 Handle<FixedArray> combined_keys = isolate->factory()->NewFixedArray(
80 own_keys_length + prototype_chain_keys_length);
81 if (own_keys_length != 0) {
82 FixedArray::CopyElements(isolate, *combined_keys, 0, *own_keys, 0,
83 own_keys_length);
84 }
85 int target_keys_length = own_keys_length;
86 for (int i = 0; i < prototype_chain_keys_length; i++) {
87 target_keys_length += AddKey(prototype_chain_keys->get(i), combined_keys,
88 descs, nof_descriptors, target_keys_length);
89 }
90 return FixedArray::RightTrimOrEmpty(isolate, combined_keys,
91 target_keys_length);
92}
93
94} // namespace
95
96// static
99 PropertyFilter filter, GetKeysConversion keys_conversion, bool is_for_in,
100 bool skip_indices) {
101 FastKeyAccumulator accumulator(isolate, object, mode, filter, is_for_in,
102 skip_indices);
103 return accumulator.GetKeys(keys_conversion);
104}
105
107 if (keys_.is_null()) {
108 return isolate_->factory()->empty_fixed_array();
109 }
110 USE(ContainsOnlyValidKeys);
113 DCHECK(ContainsOnlyValidKeys(result));
114
117 ->set_prototype_chain_enum_cache(*result);
120 DCHECK(first_prototype_map_->IsPrototypeValidityCellValid());
121 }
122 return result;
123}
124
128
133
135 AddKeyConversion convert) {
137 if (!IsSymbol(*key)) return ExceptionStatus::kSuccess;
138 if (!Cast<Symbol>(*key)->is_private_name())
140 } else if (IsSymbol(*key)) {
142 if (Cast<Symbol>(*key)->is_private()) return ExceptionStatus::kSuccess;
143 } else if (filter_ & SKIP_STRINGS) {
145 }
146
148 if (keys_.is_null()) {
149 keys_ = OrderedHashSet::Allocate(isolate_, 16).ToHandleChecked();
150 }
151 uint32_t index;
152 if (convert == CONVERT_TO_ARRAY_INDEX && IsString(*key) &&
153 Cast<String>(key)->AsArrayIndex(&index)) {
155 }
156 MaybeHandle<OrderedHashSet> new_set_candidate =
159 if (!new_set_candidate.ToHandle(&new_set)) {
160 // Replace generic RangeError exception with a more descriptive one.
164 isolate_, NewRangeError(MessageTemplate::kTooManyProperties),
166 }
167 if (*new_set != *keys_) {
168 // The keys_ Set is converted directly to a FixedArray in GetKeys which can
169 // be left-trimmer. Hence the previous Set should not keep a pointer to the
170 // new one.
172 keys_ = new_set;
173 }
175}
176
178 AddKeyConversion convert) {
179 int add_length = array->length();
180 for (int i = 0; i < add_length; i++) {
182 RETURN_FAILURE_IF_NOT_SUCCESSFUL(AddKey(current, convert));
183 }
185}
186
188 AddKeyConversion convert) {
189 DCHECK(IsJSArray(*array_like) || array_like->HasSloppyArgumentsElements());
190 ElementsAccessor* accessor = array_like->GetElementsAccessor();
191 return accessor->AddElementsToKeyAccumulator(array_like, this, convert);
192}
193
197 PropertyFilter filter,
198 bool skip_indices) {
199 if (filter == ALL_PROPERTIES) {
200 // Nothing to do.
201 return keys;
202 }
203 Isolate* isolate = accumulator->isolate();
204 int store_position = 0;
205 for (int i = 0; i < keys->length(); ++i) {
206 DirectHandle<Name> key(Cast<Name>(keys->get(i)), isolate);
207 if (Object::FilterKey(*key, filter)) continue; // Skip this key.
208 if (skip_indices) {
209 uint32_t index;
210 if (key->AsArrayIndex(&index)) continue; // Skip this key.
211 }
212 if (filter & ONLY_ENUMERABLE) {
214 Maybe<bool> found =
215 JSProxy::GetOwnPropertyDescriptor(isolate, owner, key, &desc);
217 if (!found.FromJust()) continue;
218 if (!desc.enumerable()) {
219 accumulator->AddShadowingKey(key);
220 continue;
221 }
222 }
223 // Keep this key.
224 if (store_position != i) {
225 keys->set(store_position, *key);
226 }
227 store_position++;
228 }
229 return FixedArray::RightTrimOrEmpty(isolate, keys, store_position);
230}
231
232// Returns "nothing" in case of exception, "true" on success.
235 // Postpone the enumerable check for for-in to the ForInFilter step.
236 if (!is_for_in_) {
238 isolate_, keys,
239 FilterProxyKeys(this, proxy, keys, filter_, skip_indices_),
240 Nothing<bool>());
241 }
242 // https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
243 // As of 10.5.11.9 says, the keys collected from Proxy should not contain
244 // any duplicates. And the order of the keys is preserved by the
245 // OrderedHashTable.
247 return Just(true);
248}
249
252 // Proxies have no hidden prototype and we should not trigger the
253 // [[GetPrototypeOf]] trap on the last iteration when using
254 // AdvanceFollowingProxies.
255 if (mode_ == KeyCollectionMode::kOwnOnly && IsJSProxy(*object)) {
257 Nothing<bool>());
258 return Just(true);
259 }
260
264 for (PrototypeIterator iter(isolate_, object, kStartAtReceiver, end);
265 !iter.IsAtEnd();) {
266 // Start the shadow checks only after the first prototype has added
267 // shadowing keys.
271 Maybe<bool> result = Just(false); // Dummy initialization.
272 if (IsJSProxy(*current)) {
274 } else if (IsWasmObject(*current)) {
277 NewTypeError(MessageTemplate::kWasmObjectsAreOpaque));
278 } else {
280 DCHECK_EQ(result, Just(false)); // Stop iterating.
281 }
282 } else {
283 DCHECK(IsJSObject(*current));
285 }
287 if (!result.FromJust()) break; // |false| means "stop iterating".
288 // Iterate through proxies but ignore access checks case on API objects for
289 // OWN_ONLY keys handled in CollectOwnKeys.
290 if (!iter.AdvanceFollowingProxiesIgnoringAccessChecks()) {
291 return Nothing<bool>();
292 }
293 if (!last_non_empty_prototype_.is_null() &&
294 *last_non_empty_prototype_ == *current) {
295 break;
296 }
297 }
298 return Just(true);
299}
300
302
307
313
321
322namespace {
323
324void TrySettingEmptyEnumCache(Tagged<JSReceiver> object) {
325 Tagged<Map> map = object->map();
326 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
327 if (!map->OnlyHasSimpleProperties()) return;
328 DCHECK(IsJSObjectMap(map)); // Implied by {OnlyHasSimpleProperties}.
329 if (map->NumberOfEnumerableProperties() > 0) return;
330 map->SetEnumLength(0);
331}
332
333bool CheckAndInitializeEmptyEnumCache(Tagged<JSReceiver> object) {
334 if (object->map()->EnumLength() == kInvalidEnumCacheSentinel) {
335 TrySettingEmptyEnumCache(object);
336 }
337 if (object->map()->EnumLength() != 0) return false;
338 DCHECK(IsJSObject(object));
339 return !Cast<JSObject>(object)->HasEnumerableElements();
340}
341} // namespace
342
345 // Directly go for the fast path for OWN_ONLY keys.
346 if (mode_ == KeyCollectionMode::kOwnOnly) return;
347 // Fully walk the prototype chain and find the last prototype with keys.
352 Tagged<JSReceiver> last_prototype;
354 for (PrototypeIterator iter(isolate_, *receiver_); !iter.IsAtEnd();
355 iter.Advance()) {
356 Tagged<JSReceiver> current = iter.GetCurrent<JSReceiver>();
358 if (MayHaveElements(current)) {
359 may_have_elements_ = true;
361 }
362 }
363 bool has_no_properties = CheckAndInitializeEmptyEnumCache(current);
364 if (has_no_properties) continue;
365 last_prototype = current;
366 has_empty_prototype_ = false;
367 }
368 // Check if we should try to create/use prototype info cache.
370 if (has_prototype_info_cache_) return;
373 receiver_->map()->EnumLength() != kInvalidEnumCacheSentinel &&
374 !Cast<JSObject>(*receiver_)->HasEnumerableElements();
375 } else if (!last_prototype.is_null()) {
377 }
378}
379
380namespace {
381
382Handle<FixedArray> ReduceFixedArrayTo(Isolate* isolate,
383 Handle<FixedArray> array, int length) {
384 DCHECK_LE(length, array->length());
385 if (array->length() == length) return array;
386 return isolate->factory()->CopyFixedArrayUpTo(array, length);
387}
388
389// Initializes and directly returns the enum cache. Users of this function
390// have to make sure to never directly leak the enum cache.
391Handle<FixedArray> GetFastEnumPropertyKeys(Isolate* isolate,
392 DirectHandle<JSObject> object) {
393 DirectHandle<Map> map(object->map(), isolate);
395 map->instance_descriptors(isolate)->enum_cache()->keys(), isolate);
396
397 // Check if the {map} has a valid enum length, which implies that it
398 // must have a valid enum cache as well.
399 int enum_length = map->EnumLength();
400 if (enum_length != kInvalidEnumCacheSentinel) {
401 DCHECK(map->OnlyHasSimpleProperties());
402 DCHECK_LE(enum_length, keys->length());
403 DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
404 isolate->counters()->enum_cache_hits()->Increment();
405 return ReduceFixedArrayTo(isolate, keys, enum_length);
406 }
407
408 // Determine the actual number of enumerable properties of the {map}.
409 enum_length = map->NumberOfEnumerableProperties();
410
411 // Check if there's already a shared enum cache on the {map}s
412 // DescriptorArray with sufficient number of entries.
413 if (enum_length <= keys->length()) {
414 if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
415 isolate->counters()->enum_cache_hits()->Increment();
416 return ReduceFixedArrayTo(isolate, keys, enum_length);
417 }
418
420 enum_length);
421}
422
423template <bool fast_properties>
424MaybeHandle<FixedArray> GetOwnKeysWithElements(Isolate* isolate,
425 DirectHandle<JSObject> object,
426 GetKeysConversion convert,
427 bool skip_indices) {
429 if (fast_properties) {
430 keys = GetFastEnumPropertyKeys(isolate, object);
431 } else {
432 // TODO(cbruni): preallocate big enough array to also hold elements.
433 keys = KeyAccumulator::GetOwnEnumPropertyKeys(isolate, object);
434 }
435
436 MaybeHandle<FixedArray> result;
437 if (skip_indices) {
438 result = keys;
439 } else {
440 ElementsAccessor* accessor = object->GetElementsAccessor(isolate);
441 result = accessor->PrependElementIndices(isolate, object, keys, convert,
443 }
444
445 if (v8_flags.trace_for_in_enumerate) {
446 PrintF("| strings=%d symbols=0 elements=%u || prototypes>=1 ||\n",
447 keys->length(), result.ToHandleChecked()->length() - keys->length());
448 }
449 return result;
450}
451
452} // namespace
453
455 GetKeysConversion keys_conversion) {
456 // TODO(v8:9401): We should extend the fast path of KeyAccumulator::GetKeys to
457 // also use fast path even when filter = SKIP_SYMBOLS. We used to pass wrong
458 // filter to use fast path in cases where we tried to verify all properties
459 // are enumerable. However these checks weren't correct and passing the wrong
460 // filter led to wrong behaviour.
463 if (GetKeysFast(keys_conversion).ToHandle(&keys)) {
464 return keys;
465 }
467 }
468
470 return GetKeysWithPrototypeInfoCache(keys_conversion);
471 }
472 return GetKeysSlow(keys_conversion);
473}
474
476 GetKeysConversion keys_conversion) {
478 Tagged<Map> map = receiver_->map();
479 if (!own_only || IsCustomElementsReceiverMap(map)) {
481 }
482
483 // From this point on we are certain to only collect own keys.
484 DCHECK(IsJSObject(*receiver_));
486
487 // Do not try to use the enum-cache for dict-mode objects.
488 if (map->is_dictionary_map()) {
489 return GetOwnKeysWithElements<false>(isolate_, object, keys_conversion,
491 }
492 int enum_length = receiver_->map()->EnumLength();
493 if (enum_length == kInvalidEnumCacheSentinel) {
495 // Try initializing the enum cache and return own properties.
496 if (GetOwnKeysWithUninitializedEnumLength().ToHandle(&keys)) {
497 if (v8_flags.trace_for_in_enumerate) {
498 PrintF("| strings=%d symbols=0 elements=0 || prototypes>=1 ||\n",
499 keys->length());
500 }
502 object->map()->EnumLength() != kInvalidEnumCacheSentinel;
503 return keys;
504 }
505 }
506 // The properties-only case failed because there were probably elements on the
507 // receiver.
508 return GetOwnKeysWithElements<true>(isolate_, object, keys_conversion,
510}
511
512// static
514 Isolate* isolate, DirectHandle<Map> map, int enum_length,
515 AllocationType allocation) {
516 DCHECK_EQ(kInvalidEnumCacheSentinel, map->EnumLength());
517 DCHECK_GT(enum_length, 0);
518 DCHECK_EQ(enum_length, map->NumberOfEnumerableProperties());
519 DCHECK(!map->is_dictionary_map());
520
521 DirectHandle<DescriptorArray> descriptors(map->instance_descriptors(isolate),
522 isolate);
523
524 // The enum cache should have been a hit if the number of enumerable
525 // properties is fewer than what's already in the cache.
526 DCHECK_LT(descriptors->enum_cache()->keys()->length(), enum_length);
527 isolate->counters()->enum_cache_misses()->Increment();
528
529 // Create the keys array.
530 int index = 0;
531 bool fields_only = true;
532 Handle<FixedArray> keys =
533 isolate->factory()->NewFixedArray(enum_length, allocation);
534 for (InternalIndex i : map->IterateOwnDescriptors()) {
536 PropertyDetails details = descriptors->GetDetails(i);
537 if (details.IsDontEnum()) continue;
538 Tagged<Object> key = descriptors->GetKey(i);
539 if (IsSymbol(key)) continue;
540 keys->set(index, key);
541 if (details.location() != PropertyLocation::kField) fields_only = false;
542 index++;
543 }
544 DCHECK_EQ(index, keys->length());
545
546 // Optionally also create the indices array.
547 DirectHandle<FixedArray> indices = isolate->factory()->empty_fixed_array();
548 if (fields_only) {
549 indices = isolate->factory()->NewFixedArray(enum_length, allocation);
550 index = 0;
552 Tagged<Map> raw_map = *map;
553 Tagged<FixedArray> raw_indices = *indices;
554 Tagged<DescriptorArray> raw_descriptors = *descriptors;
555 for (InternalIndex i : raw_map->IterateOwnDescriptors()) {
556 PropertyDetails details = raw_descriptors->GetDetails(i);
557 if (details.IsDontEnum()) continue;
558 Tagged<Object> key = raw_descriptors->GetKey(i);
559 if (IsSymbol(key)) continue;
562 FieldIndex field_index = FieldIndex::ForDetails(raw_map, details);
563 raw_indices->set(index, Smi::FromInt(field_index.GetLoadByFieldIndex()));
564 index++;
565 }
566 DCHECK_EQ(index, indices->length());
567 }
568
569 DescriptorArray::InitializeOrChangeEnumCache(descriptors, isolate, keys,
570 indices, allocation);
571 if (map->OnlyHasSimpleProperties()) map->SetEnumLength(enum_length);
572 return keys;
573}
574
577 auto object = Cast<JSObject>(receiver_);
578 // Uninitialized enum length
579 Tagged<Map> map = object->map();
580 if (object->elements() != ReadOnlyRoots(isolate_).empty_fixed_array() &&
581 object->elements() !=
582 ReadOnlyRoots(isolate_).empty_slow_element_dictionary()) {
583 // Assume that there are elements.
585 }
586 int number_of_own_descriptors = map->NumberOfOwnDescriptors();
587 if (number_of_own_descriptors == 0) {
588 map->SetEnumLength(0);
589 return isolate_->factory()->empty_fixed_array();
590 }
591 // We have no elements but possibly enumerable property keys, hence we can
592 // directly initialize the enum cache.
593 Handle<FixedArray> keys = GetFastEnumPropertyKeys(isolate_, object);
594 if (is_for_in_) return keys;
595 // Do not leak the enum cache as it might end up as an elements backing store.
596 return isolate_->factory()->CopyFixedArray(keys);
597}
598
613
615 GetKeysConversion keys_conversion) {
616 Handle<FixedArray> own_keys;
617 if (may_have_elements_) {
618 MaybeHandle<FixedArray> maybe_own_keys;
619 if (receiver_->map()->is_dictionary_map()) {
620 maybe_own_keys = GetOwnKeysWithElements<false>(
621 isolate_, Cast<JSObject>(receiver_), keys_conversion, skip_indices_);
622 } else {
623 maybe_own_keys = GetOwnKeysWithElements<true>(
624 isolate_, Cast<JSObject>(receiver_), keys_conversion, skip_indices_);
625 }
626 ASSIGN_RETURN_ON_EXCEPTION(isolate_, own_keys, maybe_own_keys);
627 } else {
630 }
631 Handle<FixedArray> prototype_chain_keys;
633 prototype_chain_keys =
636 ->prototype_chain_enum_cache()),
637 isolate_);
638 } else {
639 KeyAccumulator accumulator(isolate_, mode_, filter_);
640 accumulator.set_is_for_in(is_for_in_);
641 accumulator.set_skip_indices(skip_indices_);
644 accumulator.set_receiver(receiver_);
649 prototype_chain_keys = accumulator.GetKeys(keys_conversion);
650 }
651 Handle<FixedArray> result = CombineKeys(
652 isolate_, own_keys, prototype_chain_keys, receiver_, may_have_elements_);
653 if (is_for_in_ && own_keys.is_identical_to(result)) {
654 // Don't leak the enumeration cache without the receiver since it might get
655 // trimmed otherwise.
656 return isolate_->factory()->CopyFixedArrayUpTo(result, result->length());
657 }
658 return result;
659}
660
662 if (!IsJSObject(receiver)) return true;
664 if (object->HasEnumerableElements()) return true;
665 if (object->HasIndexedInterceptor()) return true;
666 return false;
667}
668
673 if (!object->HasFastProperties()) return false;
674 if (object->HasNamedInterceptor()) return false;
675 if (IsAccessCheckNeeded(*object) &&
677 return false;
678 }
680 Tagged<HeapObject> prototype = receiver->map(isolate_)->prototype();
681 if (prototype.is_null()) return false;
682 Tagged<Map> maybe_proto_map = prototype->map(isolate_);
683 if (!maybe_proto_map->is_prototype_map()) return false;
684 Tagged<PrototypeInfo> prototype_info;
685 if (!maybe_proto_map->TryGetPrototypeInfo(&prototype_info)) return false;
686
688 first_prototype_map_ = direct_handle(maybe_proto_map, isolate_);
690 maybe_proto_map->IsPrototypeValidityCellValid() &&
691 IsFixedArray(prototype_info->prototype_chain_enum_cache());
692 return true;
693}
694
699 IndexedOrNamed type) {
700 DCHECK(IsJSArray(*result) || result->HasSloppyArgumentsElements());
701 ElementsAccessor* accessor = result->GetElementsAccessor();
702
703 size_t length = accessor->GetCapacity(*result, result->elements());
704 for (InternalIndex entry : InternalIndex::Range(length)) {
705 if (!accessor->HasEntry(*result, entry)) continue;
706
707 // args are invalid after args.Call(), create a new one in every iteration.
708 // Query callbacks are not expected to have side effects.
709 PropertyCallbackArguments args(isolate_, interceptor->data(), *receiver,
710 *object, Just(kDontThrow));
711 DirectHandle<Object> element = accessor->Get(isolate_, result, entry);
712 DirectHandle<Object> attributes;
713 if (type == kIndexed) {
714 uint32_t number;
715 CHECK(Object::ToUint32(*element, &number));
716 attributes = args.CallIndexedQuery(interceptor, number);
717 } else {
718 CHECK(IsName(*element));
719 attributes = args.CallNamedQuery(interceptor, Cast<Name>(element));
720 }
721 // An exception was thrown in the interceptor. Propagate.
723
724 if (!attributes.is_null()) {
725 int32_t value;
726 CHECK(Object::ToInt32(*attributes, &value));
727 if ((value & DONT_ENUM) == 0) {
729 }
730 }
731 }
733}
734
735// Returns |true| on success, |nothing| on exception.
739 PropertyCallbackArguments enum_args(isolate_, interceptor->data(), *receiver,
740 *object, Just(kDontThrow));
741
742 DCHECK_EQ(interceptor->is_named(), type == kNamed);
743 if (!interceptor->has_enumerator()) {
744 return Just(true);
745 }
747 if (type == kIndexed) {
748 maybe_result = enum_args.CallIndexedEnumerator(interceptor);
749 } else {
750 DCHECK_EQ(type, kNamed);
751 maybe_result = enum_args.CallNamedEnumerator(interceptor);
752 }
753 // An exception was thrown in the interceptor. Propagate.
755 if (IsUndefined(*maybe_result)) return Just(true);
756 DCHECK(IsJSObject(*maybe_result));
758
759 // Request was successfully intercepted, so accept potential side effects
760 // happened up to this point.
761 enum_args.AcceptSideEffects();
762
763 if ((filter_ & ONLY_ENUMERABLE) && interceptor->has_query()) {
765 receiver, object, interceptor, result, type));
766 } else {
769 }
770 return Just(true);
771}
772
775 IndexedOrNamed type) {
776 if (type == kIndexed) {
777 if (!object->HasIndexedInterceptor()) return Just(true);
778 } else {
779 if (!object->HasNamedInterceptor()) return Just(true);
780 }
782 type == kIndexed ? object->GetIndexedInterceptor()
783 : object->GetNamedInterceptor(),
784 isolate_);
785 return CollectInterceptorKeysInternal(receiver, object, interceptor, type);
786}
787
790 if (filter_ & SKIP_STRINGS || skip_indices_) return Just(true);
791
792 ElementsAccessor* accessor = object->GetElementsAccessor();
794 accessor->CollectElementIndices(object, this));
796}
797
798namespace {
799
800template <bool skip_symbols>
801std::optional<int> CollectOwnPropertyNamesInternal(
803 DirectHandle<DescriptorArray> descs, int start_index, int limit) {
804 AllowGarbageCollection allow_gc;
805 int first_skipped = -1;
806 PropertyFilter filter = keys->filter();
807 KeyCollectionMode mode = keys->mode();
808 for (InternalIndex i : InternalIndex::Range(start_index, limit)) {
809 bool is_shadowing_key = false;
810 PropertyDetails details = descs->GetDetails(i);
811
812 if ((int{details.attributes()} & filter) != 0) {
814 is_shadowing_key = true;
815 } else {
816 continue;
817 }
818 }
819
820 Tagged<Name> key = descs->GetKey(i);
821 if (skip_symbols == IsSymbol(key)) {
822 if (first_skipped == -1) first_skipped = i.as_int();
823 continue;
824 }
825 if (Object::FilterKey(key, keys->filter())) continue;
826
827 if (is_shadowing_key) {
828 // This might allocate, but {key} is not used afterwards.
829 keys->AddShadowingKey(key, &allow_gc);
830 continue;
831 } else {
832 if (keys->AddKey(key, DO_NOT_CONVERT) != ExceptionStatus::kSuccess) {
833 return std::optional<int>();
834 }
835 }
836 }
837 return first_skipped;
838}
839
840// Logic shared between different specializations of CopyEnumKeysTo.
841template <typename Dictionary>
842void CommonCopyEnumKeysTo(Isolate* isolate, DirectHandle<Dictionary> dictionary,
843 DirectHandle<FixedArray> storage,
844 KeyCollectionMode mode, KeyAccumulator* accumulator) {
845 DCHECK_IMPLIES(mode != KeyCollectionMode::kOwnOnly, accumulator != nullptr);
846 int length = storage->length();
847 int properties = 0;
848 ReadOnlyRoots roots(isolate);
849
850 AllowGarbageCollection allow_gc;
851 for (InternalIndex i : dictionary->IterateEntries()) {
853 if (!dictionary->ToKey(roots, i, &key)) continue;
854 bool is_shadowing_key = false;
855 if (IsSymbol(key)) continue;
856 PropertyDetails details = dictionary->DetailsAt(i);
857 if (details.IsDontEnum()) {
859 is_shadowing_key = true;
860 } else {
861 continue;
862 }
863 }
864 if (is_shadowing_key) {
865 // This might allocate, but {key} is not used afterwards.
866 accumulator->AddShadowingKey(key, &allow_gc);
867 continue;
868 } else {
869 if (Dictionary::kIsOrderedDictionaryType) {
870 storage->set(properties, Cast<Name>(key));
871 } else {
872 // If the dictionary does not store elements in enumeration order,
873 // we need to sort it afterwards in CopyEnumKeysTo. To enable this we
874 // need to store indices at this point, rather than the values at the
875 // given indices.
876 storage->set(properties, Smi::FromInt(i.as_int()));
877 }
878 }
879 properties++;
880 if (mode == KeyCollectionMode::kOwnOnly && properties == length) break;
881 }
882
883 CHECK_EQ(length, properties);
884}
885
886// Copies enumerable keys to preallocated fixed array.
887// Does not throw for uninitialized exports in module namespace objects, so
888// this has to be checked separately.
889template <typename Dictionary>
890void CopyEnumKeysTo(Isolate* isolate, DirectHandle<Dictionary> dictionary,
891 DirectHandle<FixedArray> storage, KeyCollectionMode mode,
892 KeyAccumulator* accumulator) {
893 static_assert(!Dictionary::kIsOrderedDictionaryType);
894
895 CommonCopyEnumKeysTo<Dictionary>(isolate, dictionary, storage, mode,
896 accumulator);
897
898 int length = storage->length();
899
901 Tagged<Dictionary> raw_dictionary = *dictionary;
902 Tagged<FixedArray> raw_storage = *storage;
903 EnumIndexComparator<Dictionary> cmp(raw_dictionary);
904 // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and
905 // store operations that are safe for concurrent marking.
906 AtomicSlot start(storage->RawFieldOfFirstElement());
907 std::sort(start, start + length, cmp);
908 for (int i = 0; i < length; i++) {
909 InternalIndex index(Smi::ToInt(raw_storage->get(i)));
910 raw_storage->set(i, raw_dictionary->NameAt(index));
911 }
912}
913
914template <>
915void CopyEnumKeysTo(Isolate* isolate,
916 DirectHandle<SwissNameDictionary> dictionary,
917 DirectHandle<FixedArray> storage, KeyCollectionMode mode,
918 KeyAccumulator* accumulator) {
919 CommonCopyEnumKeysTo<SwissNameDictionary>(isolate, dictionary, storage, mode,
920 accumulator);
921
922 // No need to sort, as CommonCopyEnumKeysTo on OrderedNameDictionary
923 // adds entries to |storage| in the dict's insertion order
924 // Further, the template argument true above means that |storage|
925 // now contains the actual values from |dictionary|, rather than indices.
926}
927
928template <class T>
929Handle<FixedArray> GetOwnEnumPropertyDictionaryKeys(
930 Isolate* isolate, KeyCollectionMode mode, KeyAccumulator* accumulator,
931 DirectHandle<JSObject> object, Tagged<T> raw_dictionary) {
932 DirectHandle<T> dictionary(raw_dictionary, isolate);
933 if (dictionary->NumberOfElements() == 0) {
934 return isolate->factory()->empty_fixed_array();
935 }
936 int length = dictionary->NumberOfEnumerableProperties();
937 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(length);
938 CopyEnumKeysTo(isolate, dictionary, storage, mode, accumulator);
939 return storage;
940}
941
942// Collect the keys from |dictionary| into |keys|, in ascending chronological
943// order of property creation.
944template <typename Dictionary>
945ExceptionStatus CollectKeysFromDictionary(DirectHandle<Dictionary> dictionary,
946 KeyAccumulator* keys) {
947 Isolate* isolate = keys->isolate();
948 ReadOnlyRoots roots(isolate);
949 // TODO(jkummerow): Consider using a std::unique_ptr<InternalIndex[]> instead.
950 DirectHandle<FixedArray> array =
951 isolate->factory()->NewFixedArray(dictionary->NumberOfElements());
952 int array_size = 0;
953 PropertyFilter filter = keys->filter();
954 // Handle enumerable strings in CopyEnumKeysTo.
955 DCHECK_NE(keys->filter(), ENUMERABLE_STRINGS);
956 {
958 for (InternalIndex i : dictionary->IterateEntries()) {
960 Tagged<Dictionary> raw_dictionary = *dictionary;
961 if (!raw_dictionary->ToKey(roots, i, &key)) continue;
962 if (Object::FilterKey(key, filter)) continue;
963 PropertyDetails details = raw_dictionary->DetailsAt(i);
964 if ((int{details.attributes()} & filter) != 0) {
966 // This might allocate, but {key} is not used afterwards.
967 keys->AddShadowingKey(key, &gc);
968 continue;
969 }
970 // TODO(emrich): consider storing keys instead of indices into the array
971 // in case of ordered dictionary type.
972 array->set(array_size++, Smi::FromInt(i.as_int()));
973 }
974 if (!Dictionary::kIsOrderedDictionaryType) {
975 // Sorting only needed if it's an unordered dictionary,
976 // otherwise we traversed elements in insertion order
977
978 EnumIndexComparator<Dictionary> cmp(*dictionary);
979 // Use AtomicSlot wrapper to ensure that std::sort uses atomic load and
980 // store operations that are safe for concurrent marking.
981 AtomicSlot start(array->RawFieldOfFirstElement());
982 std::sort(start, start + array_size, cmp);
983 }
984 }
985
986 bool has_seen_symbol = false;
987 for (int i = 0; i < array_size; i++) {
988 InternalIndex index(Smi::ToInt(array->get(i)));
989 Tagged<Object> key = dictionary->NameAt(index);
990 if (IsSymbol(key)) {
991 has_seen_symbol = true;
992 continue;
993 }
994 ExceptionStatus status = keys->AddKey(key, DO_NOT_CONVERT);
995 if (!status) return status;
996 }
997 if (has_seen_symbol) {
998 for (int i = 0; i < array_size; i++) {
999 InternalIndex index(Smi::ToInt(array->get(i)));
1000 Tagged<Object> key = dictionary->NameAt(index);
1001 if (!IsSymbol(key)) continue;
1002 ExceptionStatus status = keys->AddKey(key, DO_NOT_CONVERT);
1003 if (!status) return status;
1004 }
1005 }
1007}
1008
1009} // namespace
1010
1013 if (filter_ == ENUMERABLE_STRINGS) {
1014 DirectHandle<FixedArray> enum_keys;
1015 if (object->HasFastProperties()) {
1017 // If the number of properties equals the length of enumerable properties
1018 // we do not have to filter out non-enumerable ones
1019 Tagged<Map> map = object->map();
1020 int nof_descriptors = map->NumberOfOwnDescriptors();
1021 if (enum_keys->length() != nof_descriptors) {
1022 if (map->prototype(isolate_) != ReadOnlyRoots(isolate_).null_value()) {
1023 AllowGarbageCollection allow_gc;
1025 map->instance_descriptors(isolate_), isolate_);
1026 for (InternalIndex i : InternalIndex::Range(nof_descriptors)) {
1027 PropertyDetails details = descs->GetDetails(i);
1028 if (!details.IsDontEnum()) continue;
1029 this->AddShadowingKey(descs->GetKey(i), &allow_gc);
1030 }
1031 }
1032 }
1033 } else if (IsJSGlobalObject(*object)) {
1034 enum_keys = GetOwnEnumPropertyDictionaryKeys(
1035 isolate_, mode_, this, object,
1036 Cast<JSGlobalObject>(*object)->global_dictionary(kAcquireLoad));
1038 enum_keys = GetOwnEnumPropertyDictionaryKeys(
1039 isolate_, mode_, this, object, object->property_dictionary_swiss());
1040 } else {
1041 enum_keys = GetOwnEnumPropertyDictionaryKeys(
1042 isolate_, mode_, this, object, object->property_dictionary());
1043 }
1044 if (IsJSModuleNamespace(*object)) {
1045 // Simulate [[GetOwnProperty]] for establishing enumerability, which
1046 // throws for uninitialized exports.
1047 for (int i = 0, n = enum_keys->length(); i < n; ++i) {
1048 DirectHandle<String> key(Cast<String>(enum_keys->get(i)), isolate_);
1049 if (Cast<JSModuleNamespace>(object)
1050 ->GetExport(isolate(), key)
1051 .is_null()) {
1052 return Nothing<bool>();
1053 }
1054 }
1055 }
1057 } else {
1058 if (object->HasFastProperties()) {
1059 int limit = object->map()->NumberOfOwnDescriptors();
1061 object->map()->instance_descriptors(isolate_), isolate_);
1062 // First collect the strings,
1063 std::optional<int> first_symbol =
1064 CollectOwnPropertyNamesInternal<true>(object, this, descs, 0, limit);
1065 // then the symbols.
1067 if (first_symbol.value() != -1) {
1068 RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectOwnPropertyNamesInternal<false>(
1069 object, this, descs, first_symbol.value(), limit));
1070 }
1071 } else if (IsJSGlobalObject(*object)) {
1072 RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1074 Cast<JSGlobalObject>(*object)->global_dictionary(kAcquireLoad),
1075 isolate_),
1076 this));
1078 RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1079 direct_handle(object->property_dictionary_swiss(), isolate_), this));
1080 } else {
1081 RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1082 direct_handle(object->property_dictionary(), isolate_), this));
1083 }
1084 }
1085 // Add the property keys from the interceptor.
1086 return CollectInterceptorKeys(receiver, object, kNamed);
1087}
1088
1092 if (object->HasFastProperties()) {
1093 int limit = object->map()->NumberOfOwnDescriptors();
1095 object->map()->instance_descriptors(isolate_), isolate_);
1096 CollectOwnPropertyNamesInternal<false>(object, this, descs, 0, limit);
1097 } else if (IsJSGlobalObject(*object)) {
1098 RETURN_FAILURE_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1100 Cast<JSGlobalObject>(*object)->global_dictionary(kAcquireLoad),
1101 isolate_),
1102 this));
1104 RETURN_FAILURE_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1105 direct_handle(object->property_dictionary_swiss(), isolate_), this));
1106 } else {
1107 RETURN_FAILURE_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1108 direct_handle(object->property_dictionary(), isolate_), this));
1109 }
1111}
1112
1114 DirectHandle<AccessCheckInfo> access_check_info,
1116 if (!skip_indices_) {
1119 receiver, object,
1121 Cast<InterceptorInfo>(access_check_info->indexed_interceptor()),
1122 isolate_),
1123 kIndexed)),
1124 Nothing<bool>());
1125 }
1127 receiver, object,
1129 access_check_info->named_interceptor()),
1130 isolate_),
1131 kNamed)),
1132 Nothing<bool>());
1133 return Just(true);
1134}
1135
1136// Returns |true| on success, |false| if prototype walking should be stopped,
1137// |nothing| if an exception was thrown.
1139 DirectHandle<JSObject> object) {
1140 // Check access rights if required.
1141 if (IsAccessCheckNeeded(*object) &&
1142 !isolate_->MayAccess(isolate_->native_context(), object)) {
1143 // The cross-origin spec says that [[Enumerate]] shall return an empty
1144 // iterator when it doesn't have access...
1146 return Just(false);
1147 }
1148 // ...whereas [[OwnPropertyKeys]] shall return allowlisted properties.
1150 DirectHandle<AccessCheckInfo> access_check_info;
1151 {
1153 Tagged<AccessCheckInfo> maybe_info =
1155 if (!maybe_info.is_null()) {
1156 access_check_info = direct_handle(maybe_info, isolate_);
1157 }
1158 }
1159 // We always have both kinds of interceptors or none.
1160 if (!access_check_info.is_null() &&
1161 access_check_info->named_interceptor() != Tagged<Object>()) {
1163 receiver, object),
1164 Nothing<bool>());
1165 }
1166 return Just(false);
1167 }
1170 return Just(true);
1171 }
1172
1173 if (may_have_elements_) {
1175 }
1177 return Just(true);
1178}
1179
1180// static
1182 Isolate* isolate, DirectHandle<JSObject> object) {
1183 if (object->HasFastProperties()) {
1184 return GetFastEnumPropertyKeys(isolate, object);
1185 } else if (IsJSGlobalObject(*object)) {
1186 return GetOwnEnumPropertyDictionaryKeys(
1187 isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
1188 Cast<JSGlobalObject>(*object)->global_dictionary(kAcquireLoad));
1190 return GetOwnEnumPropertyDictionaryKeys(
1191 isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
1192 object->property_dictionary_swiss());
1193 } else {
1194 return GetOwnEnumPropertyDictionaryKeys(
1195 isolate, KeyCollectionMode::kOwnOnly, nullptr, object,
1196 object->property_dictionary());
1197 }
1198}
1199
1200namespace {
1201
1202class NameComparator {
1203 public:
1204 explicit NameComparator(Isolate* isolate) : isolate_(isolate) {}
1205
1206 bool operator()(uint32_t hash1, uint32_t hash2,
1207 const DirectHandle<Name>& key1,
1208 const DirectHandle<Name>& key2) const {
1209 return Name::Equals(isolate_, key1, key2);
1210 }
1211
1212 private:
1213 Isolate* isolate_;
1214};
1215
1216} // namespace
1217
1218// ES6 #sec-proxy-object-internal-methods-and-internal-slots-ownpropertykeys
1219// Returns |true| on success, |nothing| in case of exception.
1223 if (filter_ == PRIVATE_NAMES_ONLY) {
1225 RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1226 direct_handle(proxy->property_dictionary_swiss(), isolate_), this));
1227 } else {
1228 RETURN_NOTHING_IF_NOT_SUCCESSFUL(CollectKeysFromDictionary(
1229 direct_handle(proxy->property_dictionary(), isolate_), this));
1230 }
1231 return Just(true);
1232 }
1233
1234 // 1. Let handler be the value of the [[ProxyHandler]] internal slot of O.
1235 DirectHandle<Object> handler(proxy->handler(), isolate_);
1236 // 2. If handler is null, throw a TypeError exception.
1237 // 3. Assert: Type(handler) is Object.
1238 if (proxy->IsRevoked()) {
1239 isolate_->Throw(*isolate_->factory()->NewTypeError(
1240 MessageTemplate::kProxyRevoked, isolate_->factory()->ownKeys_string()));
1241 return Nothing<bool>();
1242 }
1243 // 4. Let target be the value of the [[ProxyTarget]] internal slot of O.
1245 // 5. Let trap be ? GetMethod(handler, "ownKeys").
1248 isolate_, trap,
1250 isolate_->factory()->ownKeys_string()),
1251 Nothing<bool>());
1252 // 6. If trap is undefined, then
1253 if (IsUndefined(*trap, isolate_)) {
1254 // 6a. Return target.[[OwnPropertyKeys]]().
1255 return CollectOwnJSProxyTargetKeys(proxy, target);
1256 }
1257 // 7. Let trapResultArray be Call(trap, handler, «target»).
1258 DirectHandle<Object> trap_result_array;
1259 DirectHandle<Object> args[] = {target};
1261 isolate_, trap_result_array,
1263 Nothing<bool>());
1264 // 8. Let trapResult be ? CreateListFromArrayLike(trapResultArray,
1265 // «String, Symbol»).
1266 DirectHandle<FixedArray> trap_result;
1268 isolate_, trap_result,
1269 Object::CreateListFromArrayLike(isolate_, trap_result_array,
1271 Nothing<bool>());
1272 // 9. If trapResult contains any duplicate entries, throw a TypeError
1273 // exception. Combine with step 18
1274 // 18. Let uncheckedResultKeys be a new List which is a copy of trapResult.
1275 Zone set_zone(isolate_->allocator(), ZONE_NAME);
1276
1277 const int kPresent = 1;
1278 const int kGone = 0;
1279 using ZoneHashMapImpl =
1280 base::TemplateHashMapImpl<Handle<Name>, int, NameComparator,
1282 ZoneHashMapImpl unchecked_result_keys(
1283 ZoneHashMapImpl::kDefaultHashMapCapacity, NameComparator(isolate_),
1284 ZoneAllocationPolicy(&set_zone));
1285 int unchecked_result_keys_size = 0;
1286 for (int i = 0; i < trap_result->length(); ++i) {
1287 Handle<Name> key(Cast<Name>(trap_result->get(i)), isolate_);
1288 auto entry = unchecked_result_keys.LookupOrInsert(key, key->EnsureHash());
1289 if (entry->value != kPresent) {
1290 entry->value = kPresent;
1291 unchecked_result_keys_size++;
1292 } else {
1293 // found dupes, throw exception
1294 isolate_->Throw(*isolate_->factory()->NewTypeError(
1295 MessageTemplate::kProxyOwnKeysDuplicateEntries));
1296 return Nothing<bool>();
1297 }
1298 }
1299 // 10. Let extensibleTarget be ? IsExtensible(target).
1300 Maybe<bool> maybe_extensible = JSReceiver::IsExtensible(isolate_, target);
1301 MAYBE_RETURN(maybe_extensible, Nothing<bool>());
1302 bool extensible_target = maybe_extensible.FromJust();
1303 // 11. Let targetKeys be ? target.[[OwnPropertyKeys]]().
1304 DirectHandle<FixedArray> target_keys;
1306 isolate_, target_keys, JSReceiver::OwnPropertyKeys(isolate_, target),
1307 Nothing<bool>());
1308 // 12, 13. (Assert)
1309 // 14. Let targetConfigurableKeys be an empty List.
1310 // To save memory, we're reusing target_keys and will modify it in-place.
1311 DirectHandle<FixedArray> target_configurable_keys = target_keys;
1312 // 15. Let targetNonconfigurableKeys be an empty List.
1313 DirectHandle<FixedArray> target_nonconfigurable_keys =
1314 isolate_->factory()->NewFixedArray(target_keys->length());
1315 int nonconfigurable_keys_length = 0;
1316 // 16. Repeat, for each element key of targetKeys:
1317 for (int i = 0; i < target_keys->length(); ++i) {
1318 // 16a. Let desc be ? target.[[GetOwnProperty]](key).
1319 PropertyDescriptor desc;
1321 isolate_, target, direct_handle(target_keys->get(i), isolate_), &desc);
1322 MAYBE_RETURN(found, Nothing<bool>());
1323 // 16b. If desc is not undefined and desc.[[Configurable]] is false, then
1324 if (found.FromJust() && !desc.configurable()) {
1325 // 16b i. Append key as an element of targetNonconfigurableKeys.
1326 target_nonconfigurable_keys->set(nonconfigurable_keys_length,
1327 target_keys->get(i));
1328 nonconfigurable_keys_length++;
1329 // The key was moved, null it out in the original list.
1330 target_keys->set(i, Smi::zero());
1331 } else {
1332 // 16c. Else,
1333 // 16c i. Append key as an element of targetConfigurableKeys.
1334 // (No-op, just keep it in |target_keys|.)
1335 }
1336 }
1337 // 17. If extensibleTarget is true and targetNonconfigurableKeys is empty,
1338 // then:
1339 if (extensible_target && nonconfigurable_keys_length == 0) {
1340 // 17a. Return trapResult.
1341 return AddKeysFromJSProxy(proxy, trap_result);
1342 }
1343 // 18. (Done in step 9)
1344 // 19. Repeat, for each key that is an element of targetNonconfigurableKeys:
1345 for (int i = 0; i < nonconfigurable_keys_length; ++i) {
1346 Tagged<Object> raw_key = target_nonconfigurable_keys->get(i);
1348 // 19a. If key is not an element of uncheckedResultKeys, throw a
1349 // TypeError exception.
1350 auto found = unchecked_result_keys.Lookup(key, key->hash());
1351 if (found == nullptr || found->value == kGone) {
1352 isolate_->Throw(*isolate_->factory()->NewTypeError(
1353 MessageTemplate::kProxyOwnKeysMissing, key));
1354 return Nothing<bool>();
1355 }
1356 // 19b. Remove key from uncheckedResultKeys.
1357 found->value = kGone;
1358 unchecked_result_keys_size--;
1359 }
1360 // 20. If extensibleTarget is true, return trapResult.
1361 if (extensible_target) {
1362 return AddKeysFromJSProxy(proxy, trap_result);
1363 }
1364 // 21. Repeat, for each key that is an element of targetConfigurableKeys:
1365 for (int i = 0; i < target_configurable_keys->length(); ++i) {
1366 Tagged<Object> raw_key = target_configurable_keys->get(i);
1367 if (IsSmi(raw_key)) continue; // Zapped entry, was nonconfigurable.
1369 // 21a. If key is not an element of uncheckedResultKeys, throw a
1370 // TypeError exception.
1371 auto found = unchecked_result_keys.Lookup(key, key->hash());
1372 if (found == nullptr || found->value == kGone) {
1373 isolate_->Throw(*isolate_->factory()->NewTypeError(
1374 MessageTemplate::kProxyOwnKeysMissing, key));
1375 return Nothing<bool>();
1376 }
1377 // 21b. Remove key from uncheckedResultKeys.
1378 found->value = kGone;
1379 unchecked_result_keys_size--;
1380 }
1381 // 22. If uncheckedResultKeys is not empty, throw a TypeError exception.
1382 if (unchecked_result_keys_size != 0) {
1383 DCHECK_GT(unchecked_result_keys_size, 0);
1384 isolate_->Throw(*isolate_->factory()->NewTypeError(
1385 MessageTemplate::kProxyOwnKeysNonExtensible));
1386 return Nothing<bool>();
1387 }
1388 // 23. Return trapResult.
1389 return AddKeysFromJSProxy(proxy, trap_result);
1390}
1391
1405
1406#undef RETURN_NOTHING_IF_NOT_SUCCESSFUL
1407#undef RETURN_FAILURE_IF_NOT_SUCCESSFUL
1408} // namespace v8::internal
Isolate * isolate_
V8_INLINE T FromJust() const &
Definition v8-maybe.h:64
static Tagged< AccessCheckInfo > Get(Isolate *isolate, DirectHandle< JSObject > receiver)
Definition objects.cc:6594
static void InitializeOrChangeEnumCache(DirectHandle< DescriptorArray > descriptors, Isolate *isolate, DirectHandle< FixedArray > keys, DirectHandle< FixedArray > indices, AllocationType allocation_if_initialize)
Definition objects.cc:3914
V8_INLINE bool is_null() const
Definition handles.h:693
virtual Handle< Object > Get(Isolate *isolate, DirectHandle< JSObject > holder, InternalIndex entry)=0
virtual size_t GetCapacity(Tagged< JSObject > holder, Tagged< FixedArrayBase > backing_store)=0
virtual V8_WARN_UNUSED_RESULT ExceptionStatus AddElementsToKeyAccumulator(DirectHandle< JSObject > receiver, KeyAccumulator *accumulator, AddKeyConversion convert)=0
virtual V8_WARN_UNUSED_RESULT ExceptionStatus CollectElementIndices(DirectHandle< JSObject > object, DirectHandle< FixedArrayBase > backing_store, KeyAccumulator *keys)=0
virtual bool HasEntry(Tagged< JSObject > holder, InternalIndex entry)=0
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT MaybeHandle< Object > Call(Isolate *isolate, DirectHandle< Object > callable, DirectHandle< Object > receiver, base::Vector< const DirectHandle< Object > > args)
Definition execution.cc:523
Handle< Number > NewNumberFromUint(uint32_t value)
Handle< FixedArray > NewFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
Handle< FixedArray > CopyFixedArray(Handle< FixedArray > array)
Definition factory.cc:2761
Handle< FixedArray > CopyFixedArrayUpTo(DirectHandle< FixedArray > array, int new_len, AllocationType allocation=AllocationType::kYoung)
Definition factory.cc:2743
static Handle< FixedArray > InitializeFastPropertyEnumCache(Isolate *isolate, DirectHandle< Map > map, int enum_length, AllocationType allocation=AllocationType::kOld)
Definition keys.cc:513
MaybeHandle< FixedArray > GetKeys(GetKeysConversion convert=GetKeysConversion::kKeepNumbers)
Definition keys.cc:454
MaybeHandle< FixedArray > GetKeysFast(GetKeysConversion convert)
Definition keys.cc:475
MaybeHandle< FixedArray > GetOwnKeysWithUninitializedEnumLength()
Definition keys.cc:576
MaybeHandle< FixedArray > GetKeysSlow(GetKeysConversion convert)
Definition keys.cc:599
bool TryPrototypeInfoCache(DirectHandle< JSReceiver > receiver)
Definition keys.cc:669
DirectHandle< Map > first_prototype_map_
Definition keys.h:231
DirectHandle< JSReceiver > receiver_
Definition keys.h:230
DirectHandle< JSReceiver > last_non_empty_prototype_
Definition keys.h:233
DirectHandle< JSReceiver > first_prototype_
Definition keys.h:232
bool MayHaveElements(Tagged< JSReceiver > receiver)
Definition keys.cc:661
MaybeHandle< FixedArray > GetKeysWithPrototypeInfoCache(GetKeysConversion convert)
Definition keys.cc:614
KeyCollectionMode mode_
Definition keys.h:234
static FieldIndex ForDetails(Tagged< Map > map, PropertyDetails details)
static HandleType< FixedArray > RightTrimOrEmpty(Isolate *isolate, HandleType< FixedArray > array, int new_length)
void CopyElements(Isolate *isolate, int dst_index, Tagged< FixedArray > src, int src_index, int len, WriteBarrierMode mode)
V8_INLINE bool is_identical_to(const HandleBase &that) const
Definition handles-inl.h:36
AccountingAllocator * allocator()
Definition isolate.h:1979
Tagged< Object > Throw(Tagged< Object > exception, MessageLocation *location=nullptr)
Definition isolate.cc:2091
Handle< NativeContext > native_context()
Definition isolate-inl.h:48
v8::internal::Factory * factory()
Definition isolate.h:1527
bool MayAccess(DirectHandle< NativeContext > accessing_context, DirectHandle< JSObject > receiver)
Definition isolate.cc:1815
static V8_WARN_UNUSED_RESULT Maybe< bool > GetOwnPropertyDescriptor(Isolate *isolate, DirectHandle< JSProxy > proxy, DirectHandle< Name > name, PropertyDescriptor *desc)
Definition objects.cc:3490
V8_EXPORT_PRIVATE static V8_WARN_UNUSED_RESULT Maybe< bool > GetOwnPropertyDescriptor(Isolate *isolate, DirectHandle< JSReceiver > object, DirectHandle< Object > key, PropertyDescriptor *desc)
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< FixedArray > OwnPropertyKeys(Isolate *isolate, DirectHandle< JSReceiver > object)
static V8_WARN_UNUSED_RESULT Maybe< bool > IsExtensible(Isolate *isolate, DirectHandle< JSReceiver > object)
Maybe< bool > CollectOwnPropertyNames(DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object)
Definition keys.cc:1011
V8_WARN_UNUSED_RESULT ExceptionStatus CollectPrivateNames(DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object)
Definition keys.cc:1089
V8_WARN_UNUSED_RESULT ExceptionStatus FilterForEnumerableProperties(DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object, DirectHandle< InterceptorInfo > interceptor, DirectHandle< JSObject > result, IndexedOrNamed type)
Definition keys.cc:696
Maybe< bool > CollectKeys(DirectHandle< JSReceiver > receiver, DirectHandle< JSReceiver > object)
Definition keys.cc:250
Maybe< bool > CollectOwnJSProxyTargetKeys(DirectHandle< JSProxy > proxy, DirectHandle< JSReceiver > target)
Definition keys.cc:1392
void AddShadowingKey(Tagged< Object > key, AllowGarbageCollection *allow_gc)
Definition keys.cc:308
void set_may_have_elements(bool value)
Definition keys.h:156
Handle< OrderedHashSet > keys()
Definition keys.cc:125
V8_WARN_UNUSED_RESULT ExceptionStatus AddKey(Tagged< Object > key, AddKeyConversion convert=DO_NOT_CONVERT)
Definition keys.cc:129
DirectHandle< JSReceiver > receiver_
Definition keys.h:161
void set_try_prototype_info_cache(bool value)
Definition keys.h:146
KeyCollectionMode mode_
Definition keys.h:164
Maybe< bool > CollectInterceptorKeys(DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object, IndexedOrNamed type)
Definition keys.cc:773
Handle< ObjectHashSet > shadowing_keys_
Definition keys.h:163
void set_receiver(DirectHandle< JSReceiver > object)
Definition keys.h:149
PropertyFilter filter_
Definition keys.h:165
void set_last_non_empty_prototype(DirectHandle< JSReceiver > object)
Definition keys.h:153
Maybe< bool > CollectOwnJSProxyKeys(DirectHandle< JSReceiver > receiver, DirectHandle< JSProxy > proxy)
Definition keys.cc:1220
void set_is_for_in(bool value)
Definition keys.h:142
static MaybeHandle< FixedArray > GetKeys(Isolate *isolate, DirectHandle< JSReceiver > object, KeyCollectionMode mode, PropertyFilter filter, GetKeysConversion keys_conversion=GetKeysConversion::kKeepNumbers, bool is_for_in=false, bool skip_indices=false)
Definition keys.cc:97
Maybe< bool > CollectOwnKeys(DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object)
Definition keys.cc:1138
Maybe< bool > CollectAccessCheckInterceptorKeys(DirectHandle< AccessCheckInfo > access_check_info, DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object)
Definition keys.cc:1113
void set_first_prototype_map(DirectHandle< Map > value)
Definition keys.h:143
void set_skip_indices(bool value)
Definition keys.h:90
Maybe< bool > AddKeysFromJSProxy(DirectHandle< JSProxy > proxy, DirectHandle< FixedArray > keys)
Definition keys.cc:233
bool IsShadowed(DirectHandle< Object > key)
Definition keys.cc:303
Maybe< bool > CollectOwnElementIndices(DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object)
Definition keys.cc:788
static Handle< FixedArray > GetOwnEnumPropertyKeys(Isolate *isolate, DirectHandle< JSObject > object)
Definition keys.cc:1181
DirectHandle< JSReceiver > last_non_empty_prototype_
Definition keys.h:162
V8_WARN_UNUSED_RESULT ExceptionStatus AddKeys(DirectHandle< FixedArray > array, AddKeyConversion convert)
Definition keys.cc:177
Handle< OrderedHashSet > keys_
Definition keys.h:159
DirectHandle< Map > first_prototype_map_
Definition keys.h:160
Maybe< bool > CollectInterceptorKeysInternal(DirectHandle< JSReceiver > receiver, DirectHandle< JSObject > object, DirectHandle< InterceptorInfo > interceptor, IndexedOrNamed type)
Definition keys.cc:736
static Handle< UnionOf< Smi, Cell > > GetOrCreatePrototypeChainValidityCell(DirectHandle< Map > map, Isolate *isolate)
Definition map.cc:2419
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(Handle< S > *out) const
bool Equals(Tagged< Name > other)
Definition name-inl.h:76
static Handle< ObjectHashSet > Add(Isolate *isolate, Handle< ObjectHashSet > set, DirectHandle< Object > key)
Definition objects.cc:6258
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< FixedArray > CreateListFromArrayLike(Isolate *isolate, DirectHandle< Object > object, ElementTypes element_types)
Definition objects.cc:1176
static bool FilterKey(Tagged< Object > obj, PropertyFilter filter)
static V8_EXPORT_PRIVATE bool ToInt32(Tagged< Object > obj, int32_t *value)
Definition objects.cc:1438
static V8_WARN_UNUSED_RESULT MaybeDirectHandle< Object > GetMethod(Isolate *isolate, DirectHandle< JSReceiver > receiver, DirectHandle< Name > name)
Definition objects.cc:1125
static bool ToUint32(Tagged< Object > obj, uint32_t *value)
static MaybeHandle< OrderedHashSet > Allocate(IsolateT *isolate, int capacity, AllocationType allocation=AllocationType::kYoung)
static Handle< FixedArray > ConvertToKeysArray(Isolate *isolate, Handle< OrderedHashSet > table, GetKeysConversion convert)
static HandleType< OrderedHashSet >::MaybeType Add(Isolate *isolate, HandleType< OrderedHashSet > table, DirectHandle< Object > value)
DirectHandle< JSObjectOrUndefined > CallIndexedEnumerator(DirectHandle< InterceptorInfo > interceptor)
DirectHandle< JSObjectOrUndefined > CallNamedEnumerator(DirectHandle< InterceptorInfo > interceptor)
PropertyAttributes attributes() const
PropertyLocation location() const
Tagged< T > GetCurrent() const
Definition prototype.h:52
static constexpr int ToInt(const Tagged< Object > object)
Definition smi.h:33
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static constexpr Tagged< Smi > zero()
Definition smi.h:99
V8_INLINE constexpr bool is_null() const
Definition tagged.h:502
#define V8_ENABLE_SWISS_NAME_DICTIONARY_BOOL
Definition globals.h:242
int start
int end
LineAndColumn current
#define RETURN_FAILURE_IF_NOT_SUCCESSFUL(call)
Definition elements.cc:95
#define RETURN_NOTHING_IF_NOT_SUCCESSFUL(call)
Definition elements.cc:90
#define THROW_NEW_ERROR_RETURN_VALUE(isolate, call, value)
Definition isolate.h:300
#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call)
Definition isolate.h:291
#define RETURN_FAILURE(isolate, should_throw, call)
Definition isolate.h:398
#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition isolate.h:276
#define RETURN_VALUE_IF_EXCEPTION(isolate, value)
Definition isolate.h:224
#define STACK_CHECK(isolate, result_value)
Definition isolate.h:3067
#define MAYBE_RETURN(call, value)
Definition isolate.h:408
#define RETURN_VALUE_IF_EXCEPTION_DETECTOR(isolate, detector, value)
Definition isolate.h:232
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
TNode< Object > target
TNode< Object > receiver
std::map< const std::string, const std::string > map
ZoneVector< RpoNumber > & result
MovableLabel handler
std::optional< OolTrapLabel > trap
constexpr Vector< T > VectorOf(T *start, size_t size)
Definition vector.h:360
KeyCollectionMode
Definition keys.h:28
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
bool IsNumber(Tagged< Object > obj)
void PrintF(const char *format,...)
Definition utils.cc:39
GetKeysConversion
Definition keys.h:22
bool IsCustomElementsReceiverMap(Tagged< Map > map)
Tagged(T object) -> Tagged< T >
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
kStaticElementsTemplateOffset kInstancePropertiesTemplateOffset Tagged< FixedArray >
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
PerThreadAssertScopeDebugOnly< true, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > AllowGarbageCollection
static const int kInvalidEnumCacheSentinel
V8_EXPORT_PRIVATE FlagValues v8_flags
MaybeDirectHandle< FixedArray > FilterProxyKeys(KeyAccumulator *accumulator, DirectHandle< JSProxy > owner, DirectHandle< FixedArray > keys, PropertyFilter filter, bool skip_indices)
Definition keys.cc:194
V8_INLINE bool IsWasmObject(T obj, Isolate *=nullptr)
Definition objects.h:725
return value
Definition map-inl.h:893
AddKeyConversion
Definition keys.h:20
@ DO_NOT_CONVERT
Definition keys.h:20
@ CONVERT_TO_ARRAY_INDEX
Definition keys.h:20
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Local< T > Handle
Maybe< T > Nothing()
Definition v8-maybe.h:112
static constexpr AcquireLoadTag kAcquireLoad
Definition globals.h:2908
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
#define DCHECK_LE(v1, v2)
Definition logging.h:490
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define CHECK_EQ(lhs, rhs)
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define DCHECK_GT(v1, v2)
Definition logging.h:487
#define USE(...)
Definition macros.h:293
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define ZONE_NAME
Definition zone.h:22