v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
ordered-hash-table.cc
Go to the documentation of this file.
1// Copyright 2018 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
6
8#include "src/heap/heap-inl.h"
13#include "src/roots/roots.h"
14
15namespace v8 {
16namespace internal {
17
18template <class Derived, int entrysize>
20 Isolate* isolate, int capacity, AllocationType allocation) {
21 // Capacity must be a power of two, since we depend on being able
22 // to divide and multiple by 2 (kLoadFactor) to derive capacity
23 // from number of buckets. If we decide to change kLoadFactor
24 // to something other than 2, capacity should be stored as another
25 // field of this object.
26 capacity =
27 base::bits::RoundUpToPowerOfTwo32(std::max({kInitialCapacity, capacity}));
28 if (capacity > MaxCapacity()) {
29 // Throw RangeError with a generic message.
31 isolate,
32 NewRangeError(MessageTemplate::kCollectionGrowFailed,
33 isolate->factory()->empty_string()),
34 {});
35 }
36 int num_buckets = capacity / kLoadFactor;
37 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArrayWithMap(
38 Derived::GetMap(isolate->roots_table()),
39 HashTableStartIndex() + num_buckets + (capacity * kEntrySize),
40 allocation);
41 Handle<Derived> table = Cast<Derived>(backing_store);
43 Tagged<Derived> raw_table = *table;
44 for (int i = 0; i < num_buckets; ++i) {
45 raw_table->set(HashTableStartIndex() + i, Smi::FromInt(kNotFound));
46 }
47 raw_table->SetNumberOfBuckets(num_buckets);
48 raw_table->SetNumberOfElements(0);
49 raw_table->SetNumberOfDeletedElements(0);
50 return table;
51}
52
53template <class Derived, int entrysize>
55 Isolate* isolate, AllocationType allocation, RootIndex root_index) {
56 // This is only supposed to be used to create the canonical empty versions
57 // of each ordered structure, and should not be used afterwards.
58 // Requires that the map has already been set up in the roots table.
59 DCHECK(!ReadOnlyRoots(isolate).is_initialized(root_index));
60
61 Handle<FixedArray> backing_store = isolate->factory()->NewFixedArrayWithMap(
62 Derived::GetMap(isolate->roots_table()), HashTableStartIndex(),
63 allocation);
64 Handle<Derived> table = Cast<Derived>(backing_store);
66 Tagged<Derived> raw_table = *table;
67 raw_table->SetNumberOfBuckets(0);
68 raw_table->SetNumberOfElements(0);
69 raw_table->SetNumberOfDeletedElements(0);
70 return table;
71}
72
73template <class Derived, int entrysize>
74template <template <typename> typename HandleType>
75 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
76HandleType<Derived>::MaybeType
78 Isolate* isolate, HandleType<Derived> table) {
79 DCHECK(!table->IsObsolete());
81 int nof = table->NumberOfElements();
82 int nod = table->NumberOfDeletedElements();
83 int capacity = table->Capacity();
84 if ((nof + nod) < capacity) return table;
86 int new_capacity;
87 if (capacity == 0) {
88 // step from empty to minimum proper size
89 new_capacity = kInitialCapacity;
90 } else if (nod >= (capacity >> 1)) {
91 // Don't need to grow if we can simply clear out deleted entries instead.
92 // Note that we can't compact in place, though, so we always allocate
93 // a new table.
94 new_capacity = capacity;
95 } else {
96 new_capacity = capacity << 1;
97 }
98
99 return Derived::Rehash(isolate, table, new_capacity);
101
102template <class Derived, int entrysize>
103template <template <typename> typename HandleType>
104 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
106 Isolate* isolate, HandleType<Derived> table) {
107 DCHECK(!table->IsObsolete());
108
109 int nof = table->NumberOfElements();
110 int capacity = table->Capacity();
111 if (nof >= (capacity >> 2)) return table;
112 return Derived::Rehash(isolate, table, capacity / 2).ToHandleChecked();
113}
114
115template <class Derived, int entrysize>
117 Isolate* isolate, Handle<Derived> table) {
118 DCHECK(!table->IsObsolete());
119
120 AllocationType allocation_type = HeapLayout::InYoungGeneration(*table)
123
124 Handle<Derived> new_table =
125 Allocate(isolate, kInitialCapacity, allocation_type).ToHandleChecked();
126
127 if (table->NumberOfBuckets() > 0) {
128 // Don't try to modify the empty canonical table which lives in RO space.
129 table->SetNextTable(*new_table);
130 table->SetNumberOfDeletedElements(kClearedTableSentinel);
131 }
132
133 return new_table;
134}
135
136template <class Derived, int entrysize>
138 Tagged<Derived> table,
140 DCHECK_IMPLIES(entrysize == 1, IsOrderedHashSet(table));
141 DCHECK_IMPLIES(entrysize == 2, IsOrderedHashMap(table));
143 InternalIndex entry = table->FindEntry(isolate, key);
144 return entry.is_found();
145}
146
147template <class Derived, int entrysize>
149 Isolate* isolate, Tagged<Object> key) {
150 if (NumberOfElements() == 0) {
151 // This is not just an optimization but also ensures that we do the right
152 // thing if Capacity() == 0
154 }
155
156 int raw_entry;
157 // This special cases for Smi, so that we avoid the HandleScope
158 // creation below.
159 if (IsSmi(key)) {
160 uint32_t hash = ComputeUnseededHash(Smi::ToInt(key));
161 raw_entry = HashToEntryRaw(hash & Smi::kMaxValue);
162 } else {
163 HandleScope scope(isolate);
165 // If the object does not have an identity hash, it was never used as a key
166 if (IsUndefined(hash, isolate)) return InternalIndex::NotFound();
167 raw_entry = HashToEntryRaw(Smi::ToInt(hash));
168 }
169
170 // Walk the chain in the bucket to find the key.
171 while (raw_entry != kNotFound) {
172 Tagged<Object> candidate_key = KeyAt(InternalIndex(raw_entry));
173 if (Object::SameValueZero(candidate_key, key))
174 return InternalIndex(raw_entry);
175 raw_entry = NextChainEntryRaw(raw_entry);
176 }
177
179}
180
181template <template <typename> typename HandleType>
182 requires(std::is_convertible_v<HandleType<OrderedHashSet>,
184HandleType<OrderedHashSet>::MaybeType OrderedHashSet::Add(
185 Isolate* isolate, HandleType<OrderedHashSet> table,
187 int hash;
188 {
190 Tagged<Object> raw_key = *key;
191 Tagged<OrderedHashSet> raw_table = *table;
192 hash = Object::GetOrCreateHash(raw_key, isolate).value();
193 if (raw_table->NumberOfElements() > 0) {
194 int raw_entry = raw_table->HashToEntryRaw(hash);
195 // Walk the chain of the bucket and try finding the key.
196 while (raw_entry != kNotFound) {
197 Tagged<Object> candidate_key =
198 raw_table->KeyAt(InternalIndex(raw_entry));
199 // Do not add if we have the key already
200 if (Object::SameValueZero(candidate_key, raw_key)) return table;
201 raw_entry = raw_table->NextChainEntryRaw(raw_entry);
202 }
203 }
204 }
205
206 typename HandleType<OrderedHashSet>::MaybeType table_candidate =
208 if (!table_candidate.ToHandle(&table)) {
209 CHECK(isolate->has_exception());
210 return table_candidate;
213 Tagged<OrderedHashSet> raw_table = *table;
214 // Read the existing bucket values.
215 int bucket = raw_table->HashToBucket(hash);
216 int previous_entry = raw_table->HashToEntryRaw(hash);
217 int nof = raw_table->NumberOfElements();
218 // Insert a new entry at the end,
219 int new_entry = nof + raw_table->NumberOfDeletedElements();
220 int new_index = raw_table->EntryToIndexRaw(new_entry);
221 raw_table->set(new_index, *key);
222 raw_table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
223 // and point the bucket to the new entry.
224 raw_table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
225 raw_table->SetNumberOfElements(nof + 1);
226 return table;
227}
228
235
237 Isolate* isolate, Handle<OrderedHashSet> table, GetKeysConversion convert) {
238 int length = table->NumberOfElements();
239 int nof_buckets = table->NumberOfBuckets();
240 // Convert the dictionary to a linear list.
242 // From this point on table is no longer a valid OrderedHashSet.
243 result->set_map(isolate, ReadOnlyRoots(isolate).fixed_array_map());
244 int const kMaxStringTableEntries =
245 isolate->heap()->MaxNumberToStringCacheSize();
246 for (int i = 0; i < length; i++) {
247 int index = HashTableStartIndex() + nof_buckets + (i * kEntrySize);
248 Tagged<Object> key = table->get(index);
249 uint32_t index_value;
251 if (Object::ToArrayIndex(key, &index_value)) {
252 // Avoid trashing the Number2String cache if indices get very large.
253 bool use_cache = i < kMaxStringTableEntries;
254 key = *isolate->factory()->Uint32ToString(index_value, use_cache);
255 } else {
256 CHECK(IsName(key));
257 }
258 } else if (convert == GetKeysConversion::kNoNumbers) {
259 DCHECK(!Object::ToArrayIndex(key, &index_value));
260 }
261 result->set(i, key);
262 }
263 return FixedArray::RightTrimOrEmpty(isolate, result, length);
264}
265
267 return ro_roots.empty_ordered_hash_set();
268}
269
271 return ro_roots.empty_ordered_hash_map();
272}
273
274template <class Derived, int entrysize>
275template <template <typename> typename HandleType>
276 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
277HandleType<Derived>::MaybeType OrderedHashTable<Derived, entrysize>::Rehash(
278 Isolate* isolate, HandleType<Derived> table) {
280 table->Capacity());
281}
282
283template <class Derived, int entrysize>
284template <template <typename> typename HandleType>
285 requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
286HandleType<Derived>::MaybeType OrderedHashTable<Derived, entrysize>::Rehash(
287 Isolate* isolate, HandleType<Derived> table, int new_capacity) {
288 DCHECK(!table->IsObsolete());
289
290 typename HandleType<Derived>::MaybeType new_table_candidate =
291 Derived::Allocate(isolate, new_capacity,
295 DirectHandle<Derived> new_table;
296 if (!new_table_candidate.ToHandle(&new_table)) {
297 return new_table_candidate;
298 }
299 int new_buckets = new_table->NumberOfBuckets();
300 int new_entry = 0;
301 int removed_holes_index = 0;
302
304
305 for (InternalIndex old_entry : table->IterateEntries()) {
306 int old_entry_raw = old_entry.as_int();
307 Tagged<Object> key = table->KeyAt(old_entry);
308 if (IsHashTableHole(key, isolate)) {
309 table->SetRemovedIndexAt(removed_holes_index++, old_entry_raw);
310 continue;
311 }
312
314 int bucket = Smi::ToInt(hash) & (new_buckets - 1);
315 Tagged<Object> chain_entry = new_table->get(HashTableStartIndex() + bucket);
316 new_table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
317 int new_index = new_table->EntryToIndexRaw(new_entry);
318 int old_index = table->EntryToIndexRaw(old_entry_raw);
319 for (int i = 0; i < entrysize; ++i) {
320 Tagged<Object> value = table->get(old_index + i);
321 new_table->set(new_index + i, value);
322 }
323 new_table->set(new_index + kChainOffset, chain_entry);
324 ++new_entry;
325 }
326
327 DCHECK_EQ(table->NumberOfDeletedElements(), removed_holes_index);
328
329 new_table->SetNumberOfElements(table->NumberOfElements());
330 if (table->NumberOfBuckets() > 0) {
331 // Don't try to modify the empty canonical table which lives in RO space.
332 table->SetNextTable(*new_table);
333 }
334
335 return new_table_candidate;
336}
337
338template <template <typename> typename HandleType>
339 requires(std::is_convertible_v<HandleType<OrderedHashSet>,
341HandleType<OrderedHashSet>::MaybeType OrderedHashSet::Rehash(
342 Isolate* isolate, HandleType<OrderedHashSet> table) {
343 return Base::Rehash(isolate, table);
344}
345
346template <template <typename> typename HandleType>
347 requires(std::is_convertible_v<HandleType<OrderedHashSet>,
349HandleType<OrderedHashSet>::MaybeType OrderedHashSet::Rehash(
350 Isolate* isolate, HandleType<OrderedHashSet> table, int new_capacity) {
351 return Base::Rehash(isolate, table, new_capacity);
352}
353
358 int new_capacity);
363 int new_capacity);
364
365template <template <typename> typename HandleType>
366 requires(std::is_convertible_v<HandleType<OrderedHashMap>,
368HandleType<OrderedHashMap>::MaybeType OrderedHashMap::Rehash(
369 Isolate* isolate, HandleType<OrderedHashMap> table) {
370 return Base::Rehash(isolate, table);
371}
372template <template <typename> typename HandleType>
373 requires(std::is_convertible_v<HandleType<OrderedHashMap>,
375HandleType<OrderedHashMap>::MaybeType OrderedHashMap::Rehash(
376 Isolate* isolate, HandleType<OrderedHashMap> table, int new_capacity) {
377 return Base::Rehash(isolate, table, new_capacity);
378}
379
384 int new_capacity);
389 int new_capacity);
390
391template <template <typename> typename HandleType>
392 requires(std::is_convertible_v<HandleType<OrderedNameDictionary>,
394HandleType<OrderedNameDictionary>::MaybeType OrderedNameDictionary::Rehash(
395 Isolate* isolate, HandleType<OrderedNameDictionary> table,
396 int new_capacity) {
397 typename HandleType<OrderedNameDictionary>::MaybeType new_table_candidate =
398 Base::Rehash(isolate, table, new_capacity);
400 if (new_table_candidate.ToHandle(&new_table)) {
401 new_table->SetHash(table->Hash());
402 }
403 return new_table_candidate;
404}
405
409 int new_capacity);
413 int new_capacity);
414
415template <class Derived, int entrysize>
417 Tagged<Derived> table,
420 InternalIndex entry = table->FindEntry(isolate, key);
421 if (entry.is_not_found()) return false;
422
423 int nof = table->NumberOfElements();
424 int nod = table->NumberOfDeletedElements();
425 int index = table->EntryToIndex(entry);
426
427 Tagged<Object> hash_table_hole =
428 ReadOnlyRoots(isolate).hash_table_hole_value();
429 for (int i = 0; i < entrysize; ++i) {
430 table->set(index + i, hash_table_hole);
431 }
432
433 table->SetNumberOfElements(nof - 1);
434 table->SetNumberOfDeletedElements(nod + 1);
435
436 return true;
437}
438
441 Tagged<Object> key(raw_key);
443 // If the object does not have an identity hash, it was never used as a key
444 if (IsUndefined(hash, isolate)) return Smi::FromInt(-1).ptr();
445 DCHECK(IsSmi(hash));
446 DCHECK_GE(Cast<Smi>(hash).value(), 0);
447 return hash.ptr();
448}
449
453 DirectHandle<Object> value) {
454 int hash = Object::GetOrCreateHash(*key, isolate).value();
455 if (table->NumberOfElements() > 0) {
456 int raw_entry = table->HashToEntryRaw(hash);
457 // Walk the chain of the bucket and try finding the key.
458 {
460 Tagged<Object> raw_key = *key;
461 while (raw_entry != kNotFound) {
462 Tagged<Object> candidate_key = table->KeyAt(InternalIndex(raw_entry));
463 // Do not add if we have the key already
464 if (Object::SameValueZero(candidate_key, raw_key)) return table;
465 raw_entry = table->NextChainEntryRaw(raw_entry);
466 }
467 }
468 }
469
470 MaybeHandle<OrderedHashMap> table_candidate =
472 if (!table_candidate.ToHandle(&table)) {
473 return table_candidate;
474 }
476 Tagged<OrderedHashMap> raw_table = *table;
477 // Read the existing bucket values.
478 int bucket = raw_table->HashToBucket(hash);
479 int previous_entry = raw_table->HashToEntryRaw(hash);
480 int nof = raw_table->NumberOfElements();
481 // Insert a new entry at the end,
482 int new_entry = nof + raw_table->NumberOfDeletedElements();
483 int new_index = raw_table->EntryToIndexRaw(new_entry);
484 raw_table->set(new_index, *key);
485 raw_table->set(new_index + kValueOffset, *value);
486 raw_table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
487 // and point the bucket to the new entry.
488 raw_table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
489 raw_table->SetNumberOfElements(nof + 1);
490 return table;
491}
492
494 Tagged<Object> value) {
496 int index = EntryToIndex(entry);
497 this->set(index, key);
498 this->set(index + kValueOffset, value);
499}
500
501template <typename IsolateT>
505
507 Tagged<Name> raw_key = Cast<Name>(key);
508
509 if (NumberOfElements() == 0) {
510 // This is not just an optimization but also ensures that we do the right
511 // thing if Capacity() == 0
513 }
514
515 int raw_entry = HashToEntryRaw(raw_key->hash());
516 while (raw_entry != kNotFound) {
517 InternalIndex entry(raw_entry);
518 Tagged<Object> candidate_key = KeyAt(entry);
519 DCHECK(IsHashTableHole(candidate_key) ||
520 IsUniqueName(Cast<Name>(candidate_key)));
521 if (candidate_key == raw_key) return entry;
522
523 // TODO(gsathya): This is loading the bucket count from the hash
524 // table for every iteration. This should be peeled out of the
525 // loop.
526 raw_entry = NextChainEntryRaw(raw_entry);
527 }
528
530}
531
535 PropertyDetails details) {
537 DCHECK(table->FindEntry(isolate, *key).is_not_found());
538
539 MaybeHandle<OrderedNameDictionary> table_candidate =
541 if (!table_candidate.ToHandle(&table)) {
542 return table_candidate;
543 }
545 Tagged<OrderedNameDictionary> raw_table = *table;
546 // Read the existing bucket values.
547 int hash = key->hash();
548 int bucket = raw_table->HashToBucket(hash);
549 int previous_entry = raw_table->HashToEntryRaw(hash);
550 int nof = raw_table->NumberOfElements();
551 // Insert a new entry at the end,
552 int new_entry = nof + raw_table->NumberOfDeletedElements();
553 int new_index = raw_table->EntryToIndexRaw(new_entry);
554 raw_table->set(new_index, *key);
555 raw_table->set(new_index + kValueOffset, *value);
556
557 // TODO(gsathya): Optimize how PropertyDetails are stored in this
558 // dictionary to save memory (by reusing padding?) and performance
559 // (by not doing the Smi conversion).
560 raw_table->set(new_index + kPropertyDetailsOffset, details.AsSmi());
561
562 raw_table->set(new_index + kChainOffset, Smi::FromInt(previous_entry));
563 // and point the bucket to the new entry.
564 raw_table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
565 raw_table->SetNumberOfElements(nof + 1);
566 return table;
567}
568
570 Tagged<Object> value,
571 PropertyDetails details) {
573 DCHECK_IMPLIES(!IsName(key), IsHashTableHole(key));
575 int index = EntryToIndex(entry);
576 this->set(index, key);
577 this->set(index + kValueOffset, value);
578
579 // TODO(gsathya): Optimize how PropertyDetails are stored in this
580 // dictionary to save memory (by reusing padding?) and performance
581 // (by not doing the Smi conversion).
582 this->set(index + kPropertyDetailsOffset, details.AsSmi());
583}
584
587 InternalIndex entry) {
588 DCHECK(entry.is_found());
589
590 Tagged<Object> hash_table_hole =
591 ReadOnlyRoots(isolate).hash_table_hole_value();
593 table->SetEntry(entry, hash_table_hole, hash_table_hole, details);
594
595 int nof = table->NumberOfElements();
596 table->SetNumberOfElements(nof - 1);
597 int nod = table->NumberOfDeletedElements();
598 table->SetNumberOfDeletedElements(nod + 1);
599
600 return Shrink(isolate, table);
601}
602
603template <typename IsolateT>
605 IsolateT* isolate, int capacity, AllocationType allocation) {
606 return Base::Allocate(isolate, capacity, allocation);
607}
608
609template <typename IsolateT>
611 IsolateT* isolate, int capacity, AllocationType allocation) {
612 return Base::Allocate(isolate, capacity, allocation);
613}
614
616 Isolate* isolate, int capacity, AllocationType allocation) {
617 MaybeHandle<OrderedNameDictionary> table_candidate =
618 Base::Allocate(isolate, capacity, allocation);
620 if (table_candidate.ToHandle(&table)) {
621 table->SetHash(PropertyArray::kNoHashSentinel);
622 }
623 return table_candidate;
624}
625
627 Isolate* isolate, AllocationType allocation) {
628 RootIndex ri = RootIndex::kEmptyOrderedHashSet;
629 return Base::AllocateEmpty(isolate, allocation, ri);
630}
631
633 Isolate* isolate, AllocationType allocation) {
634 RootIndex ri = RootIndex::kEmptyOrderedHashMap;
635 return Base::AllocateEmpty(isolate, allocation, ri);
636}
637
639 Isolate* isolate, AllocationType allocation) {
640 RootIndex ri = RootIndex::kEmptyOrderedPropertyDictionary;
641 MaybeHandle<OrderedNameDictionary> table_candidate =
642 Base::AllocateEmpty(isolate, allocation, ri);
644 if (table_candidate.ToHandle(&table)) {
645 table->SetHash(PropertyArray::kNoHashSentinel);
646 }
647
648 return table_candidate;
649}
650
652 Isolate* isolate, int capacity, AllocationType allocation);
653
655 Isolate* isolate, int capacity, AllocationType allocation);
656
659
662
663template <>
666 Isolate* isolate, int capacity, AllocationType allocation) {
667 return isolate->factory()->NewSmallOrderedHashSet(capacity, allocation);
668}
669
670template <>
673 Isolate* isolate, int capacity, AllocationType allocation) {
674 return isolate->factory()->NewSmallOrderedHashMap(capacity, allocation);
675}
676
677template <>
680 Isolate* isolate, int capacity, AllocationType allocation) {
681 return isolate->factory()->NewSmallOrderedNameDictionary(capacity,
682 allocation);
683}
684
685template <class Derived>
687 int capacity) {
689 int num_buckets = capacity / kLoadFactor;
690 int num_chains = capacity;
691
692 SetNumberOfBuckets(num_buckets);
693 SetNumberOfElements(0);
694 SetNumberOfDeletedElements(0);
695 memset(reinterpret_cast<void*>(field_address(PaddingOffset())), 0,
696 PaddingSize());
697
698 Address hashtable_start = GetHashTableStartAddress(capacity);
699 memset(reinterpret_cast<uint8_t*>(hashtable_start), kNotFound,
700 num_buckets + num_chains);
701
702 MemsetTagged(RawField(DataTableStartOffset()),
703 ReadOnlyRoots(isolate).the_hole_value(),
704 capacity * Derived::kEntrySize);
705
706#ifdef DEBUG
707 for (int i = 0; i < num_buckets; ++i) {
708 DCHECK_EQ(kNotFound, GetFirstEntry(i));
709 }
710
711 for (int i = 0; i < num_chains; ++i) {
712 DCHECK_EQ(kNotFound, GetNextEntry(i));
713 }
714
715 for (int i = 0; i < capacity; ++i) {
716 for (int j = 0; j < Derived::kEntrySize; j++) {
717 DCHECK_EQ(ReadOnlyRoots(isolate).the_hole_value(), GetDataEntry(i, j));
718 }
719 }
720#endif // DEBUG
721}
722
724 Isolate* isolate, Handle<SmallOrderedHashSet> table,
726 if (table->HasKey(isolate, key)) return table;
727
728 if (table->UsedCapacity() >= table->Capacity()) {
730 SmallOrderedHashSet::Grow(isolate, table);
731 if (!new_table.ToHandle(&table)) {
733 }
734 }
735
737 Tagged<SmallOrderedHashSet> raw_table = *table;
738 int hash = Object::GetOrCreateHash(*key, isolate).value();
739 int nof = raw_table->NumberOfElements();
740
741 // Read the existing bucket values.
742 int bucket = raw_table->HashToBucket(hash);
743 int previous_entry = raw_table->HashToFirstEntry(hash);
744
745 // Insert a new entry at the end,
746 int new_entry = nof + raw_table->NumberOfDeletedElements();
747
748 raw_table->SetDataEntry(new_entry, SmallOrderedHashSet::kKeyIndex, *key);
749 raw_table->SetFirstEntry(bucket, new_entry);
750 raw_table->SetNextEntry(new_entry, previous_entry);
751
752 // and update book keeping.
753 raw_table->SetNumberOfElements(nof + 1);
754
755 return table;
756}
757
764
768
770 Isolate* isolate, Handle<SmallOrderedHashMap> table,
772 if (table->HasKey(isolate, key)) return table;
773
774 if (table->UsedCapacity() >= table->Capacity()) {
776 SmallOrderedHashMap::Grow(isolate, table);
777 if (!new_table.ToHandle(&table)) {
779 }
780 }
782 Tagged<SmallOrderedHashMap> raw_table = *table;
783 int hash = Object::GetOrCreateHash(*key, isolate).value();
784 int nof = raw_table->NumberOfElements();
785
786 // Read the existing bucket values.
787 int bucket = raw_table->HashToBucket(hash);
788 int previous_entry = raw_table->HashToFirstEntry(hash);
789
790 // Insert a new entry at the end,
791 int new_entry = nof + raw_table->NumberOfDeletedElements();
792
793 raw_table->SetDataEntry(new_entry, SmallOrderedHashMap::kValueIndex, *value);
794 raw_table->SetDataEntry(new_entry, SmallOrderedHashMap::kKeyIndex, *key);
795 raw_table->SetFirstEntry(bucket, new_entry);
796 raw_table->SetNextEntry(new_entry, previous_entry);
797
798 // and update book keeping.
799 raw_table->SetNumberOfElements(nof + 1);
800
801 return table;
802}
803
810
814
815template <>
818 Isolate* isolate, Tagged<Object> key) {
821 Tagged<Name> raw_key = Cast<Name>(key);
822
823 int raw_entry = HashToFirstEntry(raw_key->hash());
824
825 // Walk the chain in the bucket to find the key.
826 while (raw_entry != kNotFound) {
827 InternalIndex entry(raw_entry);
828 Tagged<Object> candidate_key = KeyAt(entry);
829 if (candidate_key == key) return entry;
830 raw_entry = GetNextEntry(raw_entry);
831 }
832
834}
835
839 PropertyDetails details) {
841 DCHECK(table->FindEntry(isolate, *key).is_not_found());
842
843 if (table->UsedCapacity() >= table->Capacity()) {
845 SmallOrderedNameDictionary::Grow(isolate, table);
846 if (!new_table.ToHandle(&table)) {
848 }
849 }
850
851 int nof = table->NumberOfElements();
852
853 // Read the existing bucket values.
854 int hash = key->hash();
855 int bucket = table->HashToBucket(hash);
856 int previous_entry = table->HashToFirstEntry(hash);
857
858 // Insert a new entry at the end,
859 int new_entry = nof + table->NumberOfDeletedElements();
860
861 table->SetDataEntry(new_entry, SmallOrderedNameDictionary::kValueIndex,
862 *value);
863 table->SetDataEntry(new_entry, SmallOrderedNameDictionary::kKeyIndex, *key);
864
865 // TODO(gsathya): PropertyDetails should be stored as part of the
866 // data table to save more memory.
867 table->SetDataEntry(new_entry,
869 details.AsSmi());
870 table->SetFirstEntry(bucket, new_entry);
871 table->SetNextEntry(new_entry, previous_entry);
872
873 // and update book keeping.
874 table->SetNumberOfElements(nof + 1);
875
876 return table;
877}
878
881 Tagged<Object> value,
882 PropertyDetails details) {
883 int raw_entry = entry.as_int();
884 DCHECK_IMPLIES(!IsName(key), IsTheHole(key));
887
888 // TODO(gsathya): PropertyDetails should be stored as part of the
889 // data table to save more memory.
891 details.AsSmi());
892}
893
894template <class Derived>
898 return FindEntry(isolate, *key).is_found();
899}
900
901template <class Derived>
903 Tagged<Derived> table,
906 InternalIndex entry = table->FindEntry(isolate, key);
907 if (entry.is_not_found()) return false;
908
909 int nof = table->NumberOfElements();
910 int nod = table->NumberOfDeletedElements();
911
912 Tagged<Object> the_hole = ReadOnlyRoots(isolate).the_hole_value();
913 for (int j = 0; j < Derived::kEntrySize; j++) {
914 table->SetDataEntry(entry.as_int(), j, the_hole);
915 }
916
917 table->SetNumberOfElements(nof - 1);
918 table->SetNumberOfDeletedElements(nod + 1);
919
920 return true;
921}
922
925 InternalIndex entry) {
926 DCHECK(entry.is_found());
927 {
929 Tagged<Object> the_hole = ReadOnlyRoots(isolate).the_hole_value();
931 table->SetEntry(entry, the_hole, the_hole, details);
932
933 int nof = table->NumberOfElements();
934 table->SetNumberOfElements(nof - 1);
935 int nod = table->NumberOfDeletedElements();
936 table->SetNumberOfDeletedElements(nod + 1);
937 }
938 return Shrink(isolate, table);
939}
940
941template <class Derived>
943 Handle<Derived> table,
944 int new_capacity) {
945 DCHECK_GE(kMaxCapacity, new_capacity);
946
948 isolate, new_capacity,
951 int new_entry = 0;
952
953 {
955 for (InternalIndex old_entry : table->IterateEntries()) {
956 Tagged<Object> key = table->KeyAt(old_entry);
957 if (IsTheHole(key, isolate)) continue;
958
959 int hash = Smi::ToInt(Object::GetHash(key));
960 int bucket = new_table->HashToBucket(hash);
961 int chain = new_table->GetFirstEntry(bucket);
962
963 new_table->SetFirstEntry(bucket, new_entry);
964 new_table->SetNextEntry(new_entry, chain);
965
966 for (int i = 0; i < Derived::kEntrySize; ++i) {
967 Tagged<Object> value = table->GetDataEntry(old_entry.as_int(), i);
968 new_table->SetDataEntry(new_entry, i, value);
969 }
970
971 ++new_entry;
972 }
973
974 new_table->SetNumberOfElements(table->NumberOfElements());
975 }
976 return new_table;
977}
978
980 Isolate* isolate, Handle<SmallOrderedHashSet> table, int new_capacity) {
982 new_capacity);
983}
984
986 Isolate* isolate, Handle<SmallOrderedHashMap> table, int new_capacity) {
988 new_capacity);
989}
990
993 int new_capacity) {
996 new_capacity);
997 new_table->SetHash(table->Hash());
998 return new_table;
999}
1000
1001template <class Derived>
1003 Handle<Derived> table) {
1004 int nof = table->NumberOfElements();
1005 int capacity = table->Capacity();
1006 if (nof >= (capacity >> 2)) return table;
1007 return Derived::Rehash(isolate, table, capacity / 2);
1008}
1009
1010template <class Derived>
1011MaybeHandle<Derived> SmallOrderedHashTable<Derived>::Grow(
1012 Isolate* isolate, Handle<Derived> table) {
1013 int capacity = table->Capacity();
1014 int new_capacity = capacity;
1015
1016 // Don't need to grow if we can simply clear out deleted entries instead.
1017 // TODO(gsathya): Compact in place, instead of allocating a new table.
1018 if (table->NumberOfDeletedElements() < (capacity >> 1)) {
1019 new_capacity = capacity << 1;
1020
1021 // The max capacity of our table is 254. We special case for 256 to
1022 // account for our growth strategy, otherwise we would only fill up
1023 // to 128 entries in our table.
1024 if (new_capacity == kGrowthHack) {
1025 new_capacity = kMaxCapacity;
1026 }
1027
1028 // We need to migrate to a bigger hash table.
1029 if (new_capacity > kMaxCapacity) {
1030 return MaybeHandle<Derived>();
1031 }
1032 }
1033
1034 return Derived::Rehash(isolate, table, new_capacity);
1035}
1036
1037template <class Derived>
1038InternalIndex SmallOrderedHashTable<Derived>::FindEntry(Isolate* isolate,
1042
1043 if (IsUndefined(hash, isolate)) return InternalIndex::NotFound();
1044 int raw_entry = HashToFirstEntry(Smi::ToInt(hash));
1045
1046 // Walk the chain in the bucket to find the key.
1047 while (raw_entry != kNotFound) {
1048 InternalIndex entry(raw_entry);
1049 Tagged<Object> candidate_key = KeyAt(entry);
1050 if (Object::SameValueZero(candidate_key, key)) return entry;
1051 raw_entry = GetNextEntry(raw_entry);
1052 }
1053 return InternalIndex::NotFound();
1054}
1055
1056template bool V8_EXPORT_PRIVATE
1058 DirectHandle<Object> key);
1061 Isolate* isolate, Handle<SmallOrderedHashSet> table, int new_capacity);
1064 Isolate* isolate, Handle<SmallOrderedHashSet> table);
1065template V8_EXPORT_PRIVATE MaybeHandle<SmallOrderedHashSet>
1067 Isolate* isolate, Handle<SmallOrderedHashSet> table);
1068template V8_EXPORT_PRIVATE void
1070 int capacity);
1071template V8_EXPORT_PRIVATE bool
1073 Isolate* isolate, Tagged<SmallOrderedHashSet> table, Tagged<Object> key);
1074
1075template V8_EXPORT_PRIVATE bool
1077 DirectHandle<Object> key);
1080 Isolate* isolate, Handle<SmallOrderedHashMap> table, int new_capacity);
1083 Isolate* isolate, Handle<SmallOrderedHashMap> table);
1084template V8_EXPORT_PRIVATE MaybeHandle<SmallOrderedHashMap>
1086 Isolate* isolate, Handle<SmallOrderedHashMap> table);
1087template V8_EXPORT_PRIVATE void
1089 int capacity);
1090
1091template V8_EXPORT_PRIVATE bool
1093 Isolate* isolate, Tagged<SmallOrderedHashMap> table, Tagged<Object> key);
1094
1095template V8_EXPORT_PRIVATE void
1097 int capacity);
1100 Isolate* isolate, Handle<SmallOrderedNameDictionary> table);
1101
1102template <class SmallTable, class LargeTable>
1103MaybeHandle<HeapObject>
1104OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(Isolate* isolate,
1105 int capacity) {
1106 if (capacity < SmallTable::kMaxCapacity) {
1107 return SmallTable::Allocate(isolate, capacity);
1108 }
1109
1110 return LargeTable::Allocate(isolate, capacity);
1111}
1112
1113template V8_EXPORT_PRIVATE MaybeHandle<HeapObject>
1114OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::Allocate(
1115 Isolate* isolate, int capacity);
1116template V8_EXPORT_PRIVATE MaybeHandle<HeapObject>
1117OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::Allocate(
1118 Isolate* isolate, int capacity);
1119template V8_EXPORT_PRIVATE MaybeHandle<HeapObject>
1120OrderedHashTableHandler<SmallOrderedNameDictionary,
1121 OrderedNameDictionary>::Allocate(Isolate* isolate,
1122 int capacity);
1123
1124template <class SmallTable, class LargeTable>
1125bool OrderedHashTableHandler<SmallTable, LargeTable>::Delete(
1126 Isolate* isolate, Handle<HeapObject> table, DirectHandle<Object> key) {
1127 if (SmallTable::Is(table)) {
1128 return SmallTable::Delete(isolate, *Cast<SmallTable>(table), *key);
1129 }
1130
1131 DCHECK(LargeTable::Is(table));
1132 // Note: Once we migrate to the a big hash table, we never migrate
1133 // down to a smaller hash table.
1134 return LargeTable::Delete(isolate, *Cast<LargeTable>(table), *key);
1135}
1136
1137template <class SmallTable, class LargeTable>
1138bool OrderedHashTableHandler<SmallTable, LargeTable>::HasKey(
1139 Isolate* isolate, Handle<HeapObject> table, Handle<Object> key) {
1140 if (SmallTable::Is(table)) {
1141 return Cast<SmallTable>(table)->HasKey(isolate, key);
1142 }
1143
1144 DCHECK(LargeTable::Is(table));
1145 return LargeTable::HasKey(isolate, Cast<LargeTable>(*table), *key);
1146}
1147
1148template bool
1149OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::HasKey(
1150 Isolate* isolate, Handle<HeapObject> table, Handle<Object> key);
1151template bool
1152OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::HasKey(
1153 Isolate* isolate, Handle<HeapObject> table, Handle<Object> key);
1154
1155template bool
1156OrderedHashTableHandler<SmallOrderedHashSet, OrderedHashSet>::Delete(
1157 Isolate* isolate, Handle<HeapObject> table, DirectHandle<Object> key);
1158template bool
1159OrderedHashTableHandler<SmallOrderedHashMap, OrderedHashMap>::Delete(
1160 Isolate* isolate, Handle<HeapObject> table, DirectHandle<Object> key);
1161template bool OrderedHashTableHandler<
1162 SmallOrderedNameDictionary,
1163 OrderedNameDictionary>::Delete(Isolate* isolate, Handle<HeapObject> table,
1164 DirectHandle<Object> key);
1165
1168 MaybeHandle<OrderedHashMap> new_table_candidate =
1169 OrderedHashMap::Allocate(isolate, OrderedHashTableMinSize);
1170 Handle<OrderedHashMap> new_table;
1171 if (!new_table_candidate.ToHandle(&new_table)) {
1172 return new_table_candidate;
1173 }
1174
1175 // TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
1176 // unhandlify this code as we preallocate the new backing store with
1177 // the proper capacity.
1178 for (InternalIndex entry : table->IterateEntries()) {
1179 DirectHandle<Object> key(table->KeyAt(entry), isolate);
1180 if (IsTheHole(*key, isolate)) continue;
1182 table->GetDataEntry(entry.as_int(), SmallOrderedHashMap::kValueIndex),
1183 isolate);
1184 new_table_candidate = OrderedHashMap::Add(isolate, new_table, key, value);
1185 if (!new_table_candidate.ToHandle(&new_table)) {
1186 return new_table_candidate;
1187 }
1188 }
1189
1190 return new_table_candidate;
1191}
1192
1195 MaybeHandle<OrderedHashSet> new_table_candidate =
1196 OrderedHashSet::Allocate(isolate, OrderedHashTableMinSize);
1197 Handle<OrderedHashSet> new_table;
1198 if (!new_table_candidate.ToHandle(&new_table)) {
1199 return new_table_candidate;
1200 }
1201
1202 // TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
1203 // unhandlify this code as we preallocate the new backing store with
1204 // the proper capacity.
1205 for (InternalIndex entry : table->IterateEntries()) {
1206 DirectHandle<Object> key(table->KeyAt(entry), isolate);
1207 if (IsTheHole(*key, isolate)) continue;
1208 new_table_candidate = OrderedHashSet::Add(isolate, new_table, key);
1209 if (!new_table_candidate.ToHandle(&new_table)) {
1210 return new_table_candidate;
1211 }
1212 }
1213
1214 return new_table_candidate;
1215}
1216
1220 MaybeHandle<OrderedNameDictionary> new_table_candidate =
1221 OrderedNameDictionary::Allocate(isolate, OrderedHashTableMinSize);
1223 if (!new_table_candidate.ToHandle(&new_table)) {
1224 return new_table_candidate;
1225 }
1226
1227 // TODO(gsathya): Optimize the lookup to not re calc offsets. Also,
1228 // unhandlify this code as we preallocate the new backing store with
1229 // the proper capacity.
1230 for (InternalIndex entry : table->IterateEntries()) {
1231 DirectHandle<Name> key(Cast<Name>(table->KeyAt(entry)), isolate);
1232 if (IsTheHole(*key, isolate)) continue;
1233 DirectHandle<Object> value(table->ValueAt(entry), isolate);
1234 PropertyDetails details = table->DetailsAt(entry);
1235 new_table_candidate =
1236 OrderedNameDictionary::Add(isolate, new_table, key, value, details);
1237 if (!new_table_candidate.ToHandle(&new_table)) {
1238 return new_table_candidate;
1239 }
1240 }
1241
1242 return new_table_candidate;
1243}
1244
1246 Handle<HeapObject> table,
1248 DirectHandle<Object> value) {
1249 if (IsSmallOrderedHashMap(*table)) {
1252 SmallOrderedHashMap::Add(isolate, small_map, key, value);
1253 if (!new_map.is_null()) return new_map.ToHandleChecked();
1254
1255 // We couldn't add to the small table, let's migrate to the
1256 // big table.
1257 MaybeHandle<OrderedHashMap> table_candidate =
1259 if (!table_candidate.ToHandle(&table)) {
1260 return table_candidate;
1261 }
1262 }
1263
1264 DCHECK(IsOrderedHashMap(*table));
1265 return OrderedHashMap::Add(isolate, Cast<OrderedHashMap>(table), key, value);
1266}
1267
1269 Handle<HeapObject> table,
1271 if (IsSmallOrderedHashSet(*table)) {
1274 SmallOrderedHashSet::Add(isolate, small_set, key);
1275 if (!new_set.is_null()) return new_set.ToHandleChecked();
1276
1277 // We couldn't add to the small table, let's migrate to the
1278 // big table.
1279 MaybeHandle<OrderedHashSet> table_candidate =
1281 if (!table_candidate.ToHandle(&table)) {
1282 return table_candidate;
1283 }
1284 }
1285
1286 DCHECK(IsOrderedHashSet(*table));
1287 return OrderedHashSet::Add(isolate, Cast<OrderedHashSet>(table), key);
1288}
1289
1292 DirectHandle<Object> value, PropertyDetails details) {
1293 if (IsSmallOrderedNameDictionary(*table)) {
1297 SmallOrderedNameDictionary::Add(isolate, small_dict, key, value,
1298 details);
1299 if (!new_dict.is_null()) return new_dict.ToHandleChecked();
1300
1301 // We couldn't add to the small table, let's migrate to the
1302 // big table.
1303 MaybeHandle<OrderedNameDictionary> table_candidate =
1305 if (!table_candidate.ToHandle(&table)) {
1306 return table_candidate;
1307 }
1308 }
1309
1310 DCHECK(IsOrderedNameDictionary(*table));
1312 key, value, details);
1313}
1314
1316 InternalIndex entry,
1318 Tagged<Object> value,
1319 PropertyDetails details) {
1321 if (IsSmallOrderedNameDictionary(table)) {
1322 return Cast<SmallOrderedNameDictionary>(table)->SetEntry(entry, key, value,
1323 details);
1324 }
1325
1326 DCHECK(IsOrderedNameDictionary(table));
1327 return Cast<OrderedNameDictionary>(table)->SetEntry(InternalIndex(entry), key,
1328 value, details);
1329}
1330
1332 Tagged<HeapObject> table,
1333 Tagged<Name> key) {
1335 if (IsSmallOrderedNameDictionary(table)) {
1336 return Cast<SmallOrderedNameDictionary>(table)->FindEntry(isolate, key);
1337 }
1338
1339 DCHECK(IsOrderedNameDictionary(table));
1340 return Cast<OrderedNameDictionary>(table)->FindEntry(isolate, key);
1341}
1342
1344 InternalIndex entry) {
1345 if (IsSmallOrderedNameDictionary(table)) {
1346 return Cast<SmallOrderedNameDictionary>(table)->ValueAt(entry);
1347 }
1348
1349 DCHECK(IsOrderedNameDictionary(table));
1350 return Cast<OrderedNameDictionary>(table)->ValueAt(entry);
1351}
1352
1354 InternalIndex entry,
1355 Tagged<Object> value) {
1356 if (IsSmallOrderedNameDictionary(table)) {
1357 return Cast<SmallOrderedNameDictionary>(table)->ValueAtPut(entry, value);
1358 }
1359
1360 DCHECK(IsOrderedNameDictionary(table));
1361 Cast<OrderedNameDictionary>(table)->ValueAtPut(entry, value);
1362}
1363
1365 Tagged<HeapObject> table, InternalIndex entry) {
1366 if (IsSmallOrderedNameDictionary(table)) {
1367 return Cast<SmallOrderedNameDictionary>(table)->DetailsAt(entry);
1368 }
1369
1370 DCHECK(IsOrderedNameDictionary(table));
1371 return Cast<OrderedNameDictionary>(table)->DetailsAt(entry);
1372}
1373
1375 InternalIndex entry,
1376 PropertyDetails details) {
1377 if (IsSmallOrderedNameDictionary(table)) {
1378 return Cast<SmallOrderedNameDictionary>(table)->DetailsAtPut(entry,
1379 details);
1380 }
1381
1382 DCHECK(IsOrderedNameDictionary(table));
1383 Cast<OrderedNameDictionary>(table)->DetailsAtPut(entry, details);
1384}
1385
1387 if (IsSmallOrderedNameDictionary(table)) {
1388 return Cast<SmallOrderedNameDictionary>(table)->Hash();
1389 }
1390
1391 DCHECK(IsOrderedNameDictionary(table));
1392 return Cast<OrderedNameDictionary>(table)->Hash();
1393}
1394
1396 if (IsSmallOrderedNameDictionary(table)) {
1397 return Cast<SmallOrderedNameDictionary>(table)->SetHash(hash);
1398 }
1399
1400 DCHECK(IsOrderedNameDictionary(table));
1401 Cast<OrderedNameDictionary>(table)->SetHash(hash);
1402}
1403
1405 InternalIndex entry) {
1406 if (IsSmallOrderedNameDictionary(table)) {
1407 return Cast<Name>(Cast<SmallOrderedNameDictionary>(table)->KeyAt(entry));
1408 }
1409
1410 return Cast<Name>(
1412}
1413
1415 if (IsSmallOrderedNameDictionary(table)) {
1416 return Cast<SmallOrderedNameDictionary>(table)->NumberOfElements();
1417 }
1418
1419 return Cast<OrderedNameDictionary>(table)->NumberOfElements();
1420}
1421
1423 if (IsSmallOrderedNameDictionary(table)) {
1424 return Cast<SmallOrderedNameDictionary>(table)->Capacity();
1425 }
1426
1427 return Cast<OrderedNameDictionary>(table)->Capacity();
1428}
1429
1431 Isolate* isolate, Handle<HeapObject> table) {
1432 if (IsSmallOrderedNameDictionary(*table)) {
1435 return SmallOrderedNameDictionary::Shrink(isolate, small_dict);
1436 }
1437
1439 return OrderedNameDictionary::Shrink(isolate, large_dict);
1440}
1441
1443 Isolate* isolate, Handle<HeapObject> table, InternalIndex entry) {
1445 if (IsSmallOrderedNameDictionary(*table)) {
1448 return SmallOrderedNameDictionary::DeleteEntry(isolate, small_dict, entry);
1449 }
1450
1452 return OrderedNameDictionary::DeleteEntry(isolate, large_dict,
1453 InternalIndex(entry));
1454}
1455
1456template <class Derived, class TableType>
1459 Tagged<TableType> table = Cast<TableType>(this->table());
1460 if (!table->IsObsolete()) return;
1461
1462 int index = Smi::ToInt(this->index());
1463 DCHECK_LE(0, index);
1464 while (table->IsObsolete()) {
1465 Tagged<TableType> next_table = table->NextTable();
1466
1467 if (index > 0) {
1468 int nod = table->NumberOfDeletedElements();
1469
1470 if (nod == TableType::kClearedTableSentinel) {
1471 index = 0;
1472 } else {
1473 int old_index = index;
1474 for (int i = 0; i < nod; ++i) {
1475 int removed_index = table->RemovedIndexAt(i);
1476 if (removed_index >= old_index) break;
1477 --index;
1478 }
1479 }
1480 }
1481
1482 table = next_table;
1483 }
1484
1485 set_table(table);
1486 set_index(Smi::FromInt(index));
1487}
1488
1489template <class Derived, class TableType>
1492 ReadOnlyRoots ro_roots = GetReadOnlyRoots();
1493
1494 Transition();
1495
1496 Tagged<TableType> table = Cast<TableType>(this->table());
1497 int index = Smi::ToInt(this->index());
1498 int used_capacity = table->UsedCapacity();
1499
1500 while (index < used_capacity &&
1501 IsHashTableHole(table->KeyAt(InternalIndex(index)), ro_roots)) {
1502 index++;
1503 }
1504
1505 set_index(Smi::FromInt(index));
1506
1507 if (index < used_capacity) return true;
1508
1509 set_table(TableType::GetEmpty(ro_roots));
1510 return false;
1511}
1512
1513template bool
1515
1516template void
1518
1519template Tagged<Object>
1521
1522template void
1524
1525template bool
1527
1528template void
1530
1531template Tagged<Object>
1533
1534template void
1536
1537// Force instantiation of template instances class.
1538// Keep this at the end of this file
1539
1540#define EXTERN_DEFINE_ORDERED_HASH_TABLE(DERIVED, ENTRY_SIZE) \
1541 template V8_EXPORT_PRIVATE MaybeIndirectHandle<DERIVED> \
1542 OrderedHashTable<DERIVED, ENTRY_SIZE>::EnsureCapacityForAdding( \
1543 Isolate* isolate, IndirectHandle<DERIVED> table); \
1544 template V8_EXPORT_PRIVATE MaybeDirectHandle<DERIVED> \
1545 OrderedHashTable<DERIVED, ENTRY_SIZE>::EnsureCapacityForAdding( \
1546 Isolate* isolate, DirectHandle<DERIVED> table); \
1547 template V8_EXPORT_PRIVATE IndirectHandle<DERIVED> \
1548 OrderedHashTable<DERIVED, ENTRY_SIZE>::Shrink( \
1549 Isolate* isolate, IndirectHandle<DERIVED> table); \
1550 template V8_EXPORT_PRIVATE DirectHandle<DERIVED> \
1551 OrderedHashTable<DERIVED, ENTRY_SIZE>::Shrink(Isolate* isolate, \
1552 DirectHandle<DERIVED> table); \
1553 template V8_EXPORT_PRIVATE Handle<DERIVED> \
1554 OrderedHashTable<DERIVED, ENTRY_SIZE>::Clear(Isolate* isolate, \
1555 Handle<DERIVED> table); \
1556 template V8_EXPORT_PRIVATE MaybeHandle<DERIVED> \
1557 OrderedHashTable<DERIVED, ENTRY_SIZE>::Allocate( \
1558 Isolate* isolate, int capacity, AllocationType allocation); \
1559 template V8_EXPORT_PRIVATE bool \
1560 OrderedHashTable<DERIVED, ENTRY_SIZE>::HasKey( \
1561 Isolate* isolate, Tagged<DERIVED> table, Tagged<Object> key); \
1562 template V8_EXPORT_PRIVATE bool \
1563 OrderedHashTable<DERIVED, ENTRY_SIZE>::Delete( \
1564 Isolate* isolate, Tagged<DERIVED> table, Tagged<Object> key); \
1565 template V8_EXPORT_PRIVATE InternalIndex \
1566 OrderedHashTable<DERIVED, ENTRY_SIZE>::FindEntry(Isolate* isolate, \
1567 Tagged<Object> key);
1568
1569EXTERN_DEFINE_ORDERED_HASH_TABLE(OrderedHashSet, 1)
1570EXTERN_DEFINE_ORDERED_HASH_TABLE(OrderedHashMap, 2)
1571EXTERN_DEFINE_ORDERED_HASH_TABLE(OrderedNameDictionary, 3)
1572
1573} // namespace internal
1574} // namespace v8
uint32_t GetHash()
Definition api.cc:4282
static HandleType< FixedArray > RightTrimOrEmpty(Isolate *isolate, HandleType< FixedArray > array, int new_length)
static V8_INLINE bool InYoungGeneration(Tagged< Object > object)
static InternalIndex NotFound()
constexpr int as_int() const
V8_INLINE Handle< T > ToHandleChecked() const
V8_WARN_UNUSED_RESULT V8_INLINE bool ToHandle(Handle< S > *out) const
static V8_WARN_UNUSED_RESULT bool ToArrayIndex(Tagged< Object > obj, uint32_t *index)
static bool SameValueZero(Tagged< Object > obj, Tagged< Object > other)
Definition objects.cc:1723
static V8_EXPORT_PRIVATE Tagged< Smi > GetOrCreateHash(Tagged< Object > obj, Isolate *isolate)
Definition objects.cc:1696
static MaybeHandle< OrderedHashMap > AdjustRepresentation(Isolate *isolate, DirectHandle< SmallOrderedHashMap > table)
static MaybeHandle< HeapObject > Add(Isolate *isolate, Handle< HeapObject > table, DirectHandle< Object > key, DirectHandle< Object > value)
static MaybeHandle< OrderedHashMap > AllocateEmpty(Isolate *isolate, AllocationType allocation=AllocationType::kReadOnly)
static MaybeHandle< OrderedHashMap > Allocate(IsolateT *isolate, int capacity, AllocationType allocation=AllocationType::kYoung)
void SetEntry(InternalIndex entry, Tagged< Object > key, Tagged< Object > value)
static Tagged< HeapObject > GetEmpty(ReadOnlyRoots ro_roots)
static Address GetHash(Isolate *isolate, Address raw_key)
static HandleType< OrderedHashMap >::MaybeType Rehash(Isolate *isolate, HandleType< OrderedHashMap > table)
static MaybeHandle< OrderedHashMap > Add(Isolate *isolate, Handle< OrderedHashMap > table, DirectHandle< Object > key, DirectHandle< Object > value)
static MaybeHandle< OrderedHashSet > AdjustRepresentation(Isolate *isolate, DirectHandle< SmallOrderedHashSet > table)
static MaybeHandle< HeapObject > Add(Isolate *isolate, Handle< HeapObject > table, DirectHandle< Object > key)
static Tagged< HeapObject > GetEmpty(ReadOnlyRoots ro_roots)
static HandleType< OrderedHashSet >::MaybeType Rehash(Isolate *isolate, HandleType< OrderedHashSet > table)
static MaybeHandle< OrderedHashSet > Allocate(IsolateT *isolate, int capacity, AllocationType allocation=AllocationType::kYoung)
static Handle< FixedArray > ConvertToKeysArray(Isolate *isolate, Handle< OrderedHashSet > table, GetKeysConversion convert)
static MaybeHandle< OrderedHashSet > AllocateEmpty(Isolate *isolate, AllocationType allocation=AllocationType::kReadOnly)
static HandleType< OrderedHashSet >::MaybeType Add(Isolate *isolate, HandleType< OrderedHashSet > table, DirectHandle< Object > value)
static HandleType< OrderedNameDictionary > Shrink(Isolate *isolate, HandleType< OrderedNameDictionary > table)
static MaybeHandle< Derived > Allocate(Isolate *isolate, int capacity, AllocationType allocation=AllocationType::kYoung)
static Handle< Derived > Clear(Isolate *isolate, Handle< Derived > table)
static HandleType< OrderedHashSet >::MaybeType EnsureCapacityForAdding(Isolate *isolate, HandleType< OrderedHashSet > table)
static HandleType< Derived >::MaybeType Rehash(Isolate *isolate, HandleType< Derived > table)
static MaybeHandle< Derived > AllocateEmpty(Isolate *isolate, AllocationType allocation, RootIndex root_ndex)
static bool HasKey(Isolate *isolate, Tagged< Derived > table, Tagged< Object > key)
InternalIndex FindEntry(Isolate *isolate, Tagged< Object > key)
static bool Delete(Isolate *isolate, Tagged< Derived > table, Tagged< Object > key)
static Tagged< Object > ValueAt(Tagged< HeapObject > table, InternalIndex entry)
static MaybeHandle< OrderedNameDictionary > AdjustRepresentation(Isolate *isolate, DirectHandle< SmallOrderedNameDictionary > table)
static DirectHandle< HeapObject > Shrink(Isolate *isolate, Handle< HeapObject > table)
static void DetailsAtPut(Tagged< HeapObject > table, InternalIndex entry, PropertyDetails value)
static Tagged< Name > KeyAt(Tagged< HeapObject > table, InternalIndex entry)
static PropertyDetails DetailsAt(Tagged< HeapObject > table, InternalIndex entry)
static int Capacity(Tagged< HeapObject > table)
static void ValueAtPut(Tagged< HeapObject > table, InternalIndex entry, Tagged< Object > value)
static int Hash(Tagged< HeapObject > table)
static int NumberOfElements(Tagged< HeapObject > table)
static void SetEntry(Tagged< HeapObject > table, InternalIndex entry, Tagged< Object > key, Tagged< Object > value, PropertyDetails details)
static MaybeHandle< HeapObject > Add(Isolate *isolate, Handle< HeapObject > table, DirectHandle< Name > key, DirectHandle< Object > value, PropertyDetails details)
static InternalIndex FindEntry(Isolate *isolate, Tagged< HeapObject > table, Tagged< Name > key)
static DirectHandle< HeapObject > DeleteEntry(Isolate *isolate, Handle< HeapObject > table, InternalIndex entry)
static void SetHash(Tagged< HeapObject > table, int hash)
InternalIndex FindEntry(IsolateT *isolate, Tagged< Object > key)
static Handle< OrderedNameDictionary > DeleteEntry(Isolate *isolate, Handle< OrderedNameDictionary > table, InternalIndex entry)
static MaybeHandle< OrderedNameDictionary > Add(Isolate *isolate, Handle< OrderedNameDictionary > table, DirectHandle< Name > key, DirectHandle< Object > value, PropertyDetails details)
static MaybeHandle< OrderedNameDictionary > Allocate(Isolate *isolate, int capacity, AllocationType allocation=AllocationType::kYoung)
static MaybeHandle< OrderedNameDictionary > AllocateEmpty(Isolate *isolate, AllocationType allocation=AllocationType::kReadOnly)
static HandleType< OrderedNameDictionary >::MaybeType Rehash(Isolate *isolate, HandleType< OrderedNameDictionary > table, int new_capacity)
void SetEntry(InternalIndex entry, Tagged< Object > key, Tagged< Object > value, PropertyDetails details)
static const int kNoHashSentinel
static constexpr PropertyDetails Empty(PropertyCellType cell_type=PropertyCellType::kNoCell)
Tagged< Smi > AsSmi() const
Definition objects-inl.h:79
static Handle< SmallOrderedHashMap > Rehash(Isolate *isolate, Handle< SmallOrderedHashMap > table, int new_capacity)
V8_EXPORT_PRIVATE bool HasKey(Isolate *isolate, DirectHandle< Object > key)
static V8_EXPORT_PRIVATE MaybeHandle< SmallOrderedHashMap > Add(Isolate *isolate, Handle< SmallOrderedHashMap > table, DirectHandle< Object > key, DirectHandle< Object > value)
static V8_EXPORT_PRIVATE bool Delete(Isolate *isolate, Tagged< SmallOrderedHashMap > table, Tagged< Object > key)
static V8_EXPORT_PRIVATE MaybeHandle< SmallOrderedHashSet > Add(Isolate *isolate, Handle< SmallOrderedHashSet > table, DirectHandle< Object > key)
V8_EXPORT_PRIVATE bool HasKey(Isolate *isolate, DirectHandle< Object > key)
static Handle< SmallOrderedHashSet > Rehash(Isolate *isolate, Handle< SmallOrderedHashSet > table, int new_capacity)
static V8_EXPORT_PRIVATE bool Delete(Isolate *isolate, Tagged< SmallOrderedHashSet > table, Tagged< Object > key)
static bool Delete(Isolate *isolate, Tagged< Derived > table, Tagged< Object > key)
void SetDataEntry(int entry, int relative_index, Tagged< Object > value)
static Handle< Derived > Rehash(Isolate *isolate, Handle< Derived > table, int new_capacity)
bool HasKey(Isolate *isolate, DirectHandle< Object > key)
InternalIndex FindEntry(Isolate *isolate, Tagged< Object > key)
static MaybeHandle< SmallOrderedHashSet > Grow(Isolate *isolate, Handle< SmallOrderedHashSet > table)
static Handle< Derived > Allocate(Isolate *isolate, int capacity, AllocationType allocation=AllocationType::kYoung)
static Handle< SmallOrderedNameDictionary > Shrink(Isolate *isolate, Handle< SmallOrderedNameDictionary > table)
void Initialize(Isolate *isolate, int capacity)
V8_EXPORT_PRIVATE void SetEntry(InternalIndex entry, Tagged< Object > key, Tagged< Object > value, PropertyDetails details)
static Handle< SmallOrderedNameDictionary > Rehash(Isolate *isolate, Handle< SmallOrderedNameDictionary > table, int new_capacity)
static V8_EXPORT_PRIVATE MaybeHandle< SmallOrderedNameDictionary > Add(Isolate *isolate, Handle< SmallOrderedNameDictionary > table, DirectHandle< Name > key, DirectHandle< Object > value, PropertyDetails details)
static V8_EXPORT_PRIVATE Handle< SmallOrderedNameDictionary > DeleteEntry(Isolate *isolate, Handle< SmallOrderedNameDictionary > table, InternalIndex entry)
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 int kMaxValue
Definition smi.h:101
void set(int index, Tagged< ElementT > value, WriteBarrierMode mode=kDefaultMode)
V8_INLINE constexpr StorageType ptr() const
V8_INLINE constexpr int32_t value() const
Definition tagged.h:427
#define THROW_NEW_ERROR_RETURN_VALUE(isolate, call, value)
Definition isolate.h:300
ZoneVector< RpoNumber > & result
V8_BASE_EXPORT constexpr uint32_t RoundUpToPowerOfTwo32(uint32_t value)
Definition bits.h:219
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
ReadOnlyRoots GetReadOnlyRoots()
Definition roots-inl.h:86
GetKeysConversion
Definition keys.h:22
Tagged(T object) -> Tagged< T >
uint32_t ComputeUnseededHash(uint32_t key)
Definition utils.h:271
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
void MemsetTagged(Tagged_t *start, Tagged< MaybeObject > value, size_t counter)
Definition slots-inl.h:486
bool IsUniqueName(Tagged< Name > obj)
return value
Definition map-inl.h:893
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
Local< T > Handle
#define EXTERN_DEFINE_ORDERED_HASH_TABLE(DERIVED, ENTRY_SIZE)
#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_GE(v1, v2)
Definition logging.h:488
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_EXPORT_PRIVATE
Definition macros.h:460