/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/objects/hash-table-inl.h
345 строк
12 KB
Michaël Zasso
deps: update V8 to 14.6.202.33
24 апр 2026, 19:01
Не верифицирован
24 апр 2026, 19:01
f1e0b83
Код
Авторство
О чём код?
// Copyright 2017 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef V8_OBJECTS_HASH_TABLE_INL_H_ #define V8_OBJECTS_HASH_TABLE_INL_H_ #include "src/objects/hash-table.h" // Include the non-inl header before the rest of the headers. #include "src/execution/isolate-utils-inl.h" #include "src/heap/heap.h" #include "src/objects/fixed-array-inl.h" #include "src/objects/heap-object-inl.h" #include "src/objects/heap-object.h" #include "src/objects/objects-inl.h" #include "src/roots/roots-inl.h" // Has to be the last include (doesn't have include guards): #include "src/objects/object-macros.h" namespace v8 { namespace internal { void EphemeronHashTable::set_key(int index, Tagged<Object> value) { DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map()); DCHECK(IsEphemeronHashTable(this)); DCHECK_GE(index, 0); DCHECK_LT(index, this->length()); objects()[index].Relaxed_Store_no_write_barrier(value); #ifndef V8_DISABLE_WRITE_BARRIERS DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(this)); WriteBarrier::ForEphemeronHashTable( Tagged(this), ObjectSlot(&objects()[index]), value, UPDATE_WRITE_BARRIER); #endif } void EphemeronHashTable::set_key(int index, Tagged<Object> value, WriteBarrierMode mode) { DCHECK_NE(GetReadOnlyRoots().fixed_cow_array_map(), map()); DCHECK(IsEphemeronHashTable(this)); DCHECK_GE(index, 0); DCHECK_LT(index, this->length()); objects()[index].Relaxed_Store_no_write_barrier(value); #ifndef V8_DISABLE_WRITE_BARRIERS #if V8_ENABLE_UNCONDITIONAL_WRITE_BARRIERS mode = UPDATE_WRITE_BARRIER; #endif DCHECK(TrustedHeapLayout::IsOwnedByAnyHeap(this)); WriteBarrier::ForEphemeronHashTable( Tagged(this), ObjectSlot(&objects()[index]), value, mode); #endif } uint32_t HashTableBase::NumberOfElements() const { return Cast<Smi>(get(kNumberOfElementsIndex)).value(); } uint32_t HashTableBase::NumberOfDeletedElements() const { return Cast<Smi>(get(kNumberOfDeletedElementsIndex)).value(); } uint32_t HashTableBase::Capacity() const { return Cast<Smi>(get(kCapacityIndex)).value(); } InternalIndex::Range HashTableBase::IterateEntries() const { return InternalIndex::Range(Capacity()); } void HashTableBase::ElementAdded() { SetNumberOfElements(NumberOfElements() + 1); } void HashTableBase::ElementRemoved() { SetNumberOfElements(NumberOfElements() - 1); SetNumberOfDeletedElements(NumberOfDeletedElements() + 1); } void HashTableBase::ElementsRemoved(int n) { SetNumberOfElements(NumberOfElements() - n); SetNumberOfDeletedElements(NumberOfDeletedElements() + n); } // static constexpr uint32_t HashTableBase::ComputeCapacity(uint32_t at_least_space_for) { // Add 50% slack to make slot collisions sufficiently unlikely. // See matching computation in HashTable::HasSufficientCapacityToAdd(). // Must be kept in sync with CodeStubAssembler::HashTableComputeCapacity(). uint32_t raw_cap = at_least_space_for + (at_least_space_for >> 1); uint32_t capacity = base::bits::RoundUpToPowerOfTwo32(raw_cap); return std::max({capacity, kMinCapacity}); } void HashTableBase::SetInitialNumberOfElements(int nof) { DCHECK_EQ(NumberOfElements(), 0); set(kNumberOfElementsIndex, Smi::FromInt(nof)); } void HashTableBase::SetNumberOfElements(int nof) { set(kNumberOfElementsIndex, Smi::FromInt(nof)); } void HashTableBase::SetNumberOfDeletedElements(int nod) { set(kNumberOfDeletedElementsIndex, Smi::FromInt(nod)); } // static template <typename Derived, typename Shape> DirectHandle<Map> HashTable<Derived, Shape>::GetMap(RootsTable& roots) { return roots.hash_table_map(); } // static DirectHandle<Map> NameToIndexHashTable::GetMap(RootsTable& roots) { return roots.name_to_index_hash_table_map(); } // static DirectHandle<Map> RegisteredSymbolTable::GetMap(RootsTable& roots) { return roots.registered_symbol_table_map(); } // static Handle<Map> EphemeronHashTable::GetMap(RootsTable& roots) { return roots.ephemeron_hash_table_map(); } template <typename Derived, typename Shape> template <typename IsolateT> InternalIndex HashTable<Derived, Shape>::FindEntry(IsolateT* isolate, Key key) { ReadOnlyRoots roots(isolate); return FindEntry(isolate, roots, key, TodoShape::Hash(roots, key)); } // Find entry for key otherwise return kNotFound. template <typename Derived, typename Shape> InternalIndex HashTable<Derived, Shape>::FindEntry(PtrComprCageBase cage_base, ReadOnlyRoots roots, Key key, int32_t hash) { DisallowGarbageCollection no_gc; uint32_t capacity = Capacity(); uint32_t count = 1; #if V8_STATIC_ROOTS_BOOL #define IS_UNDEFINED(x) IsUndefined(x) #define IS_THE_HOLE(x) IsTheHole(x) #else Tagged<Object> undefined = roots.undefined_value(); Tagged<Object> the_hole = roots.the_hole_value(); #define IS_UNDEFINED(x) (x) == undefined #define IS_THE_HOLE(x) (x) == the_hole #endif DCHECK_EQ(TodoShape::Hash(roots, key), static_cast<uint32_t>(hash)); // EnsureCapacity will guarantee the hash table is never full. for (InternalIndex entry = FirstProbe(hash, capacity);; entry = NextProbe(entry, count++, capacity)) { Tagged<Object> element = KeyAt(cage_base, entry); // Empty entry. Uses raw unchecked accessors because it is called by the // string table during bootstrapping. if (IS_UNDEFINED(element)) return InternalIndex::NotFound(); if (TodoShape::kMatchNeedsHoleCheck && IS_THE_HOLE(element)) continue; if (TodoShape::IsMatch(key, element)) return entry; } #undef IS_UNDEFINED #undef IS_THE_HOLE } template <typename Derived, typename Shape> template <typename IsolateT> InternalIndex HashTable<Derived, Shape>::FindInsertionEntry(IsolateT* isolate, uint32_t hash) { return FindInsertionEntry(isolate, ReadOnlyRoots(isolate), hash); } // static template <typename Derived, typename Shape> bool HashTable<Derived, Shape>::IsKey(ReadOnlyRoots roots, Tagged<Object> k) { // TODO(leszeks): Dictionaries that don't delete could skip the hole check. return !IsUndefined(k, roots) && !IsTheHole(k, roots); } // static template <typename Derived, typename Shape> bool HashTable<Derived, Shape>::IsKey(EarlyReadOnlyRoots roots, Tagged<Object> k) { // TODO(leszeks): Dictionaries that don't delete could skip the hole check. return !IsUndefined(k, roots) && !IsTheHole(k, roots); } template <typename Derived, typename Shape> bool HashTable<Derived, Shape>::ToKey(ReadOnlyRoots roots, InternalIndex entry, Tagged<Object>* out_k) { Tagged<Object> k = KeyAt(entry); if (!IsKey(roots, k)) return false; *out_k = TodoShape::Unwrap(k); return true; } template <typename Derived, typename Shape> bool HashTable<Derived, Shape>::ToKey(PtrComprCageBase cage_base, InternalIndex entry, Tagged<Object>* out_k) { Tagged<Object> k = KeyAt(cage_base, entry); if (!IsKey(GetReadOnlyRoots(), k)) return false; *out_k = TodoShape::Unwrap(k); return true; } template <typename Derived, typename Shape> Tagged<Object> HashTable<Derived, Shape>::KeyAt(InternalIndex entry) { PtrComprCageBase cage_base = GetPtrComprCageBase(); return KeyAt(cage_base, entry); } template <typename Derived, typename Shape> Tagged<Object> HashTable<Derived, Shape>::KeyAt(PtrComprCageBase cage_base, InternalIndex entry) { return get(EntryToIndex(entry) + kEntryKeyIndex); } template <typename Derived, typename Shape> Tagged<Object> HashTable<Derived, Shape>::KeyAt(InternalIndex entry, RelaxedLoadTag tag) { PtrComprCageBase cage_base = GetPtrComprCageBase(); return KeyAt(cage_base, entry, tag); } template <typename Derived, typename Shape> Tagged<Object> HashTable<Derived, Shape>::KeyAt(PtrComprCageBase cage_base, InternalIndex entry, RelaxedLoadTag tag) { return get(EntryToIndex(entry) + kEntryKeyIndex, tag); } template <typename Derived, typename Shape> void HashTable<Derived, Shape>::SetKeyAt(InternalIndex entry, Tagged<Object> value, WriteBarrierMode mode) { set_key(EntryToIndex(entry), value, mode); } template <typename Derived, typename Shape> void HashTable<Derived, Shape>::set_key(int index, Tagged<Object> value) { DCHECK(!IsEphemeronHashTable(this)); FixedArray::set(index, value); } template <typename Derived, typename Shape> void HashTable<Derived, Shape>::set_key(int index, Tagged<Object> value, WriteBarrierMode mode) { DCHECK(!IsEphemeronHashTable(this)); FixedArray::set(index, value, mode); } template <typename Derived, typename Shape> void HashTable<Derived, Shape>::SetCapacity(uint32_t capacity) { // To scale a computed hash code to fit within the hash table, we // use bit-wise AND with a mask, so the capacity must be positive // and non-zero. DCHECK_GT(capacity, 0); DCHECK_LE(capacity, kMaxCapacity); set(kCapacityIndex, Smi::FromInt(capacity)); } bool ObjectHashSet::Has(Isolate* isolate, DirectHandle<Object> key, int32_t hash) { return FindEntry(isolate, ReadOnlyRoots(isolate), key, hash).is_found(); } bool ObjectHashSet::Has(Isolate* isolate, DirectHandle<Object> key) { Tagged<Object> hash = Object::GetHash(*key); if (!IsSmi(hash)) return false; return FindEntry(isolate, ReadOnlyRoots(isolate), key, Smi::ToInt(hash)) .is_found(); } bool ObjectHashTableShapeBase::IsMatch(DirectHandle<Object> key, Tagged<Object> other) { return Object::SameValue(*key, other); } bool RegisteredSymbolTableShape::IsMatch(DirectHandle<String> key, Tagged<Object> value) { DCHECK(IsString(value)); return key->Equals(Cast<String>(value)); } uint32_t RegisteredSymbolTableShape::Hash(ReadOnlyRoots roots, DirectHandle<String> key) { return key->EnsureHash(); } uint32_t RegisteredSymbolTableShape::HashForObject(ReadOnlyRoots roots, Tagged<Object> object) { return Cast<String>(object)->EnsureHash(); } bool NameToIndexShape::IsMatch(Tagged<Name> key, Tagged<Object> other) { return key == other; } uint32_t NameToIndexShape::HashForObject(ReadOnlyRoots roots, Tagged<Object> other) { return Cast<Name>(other)->hash(); } uint32_t NameToIndexShape::Hash(ReadOnlyRoots roots, Tagged<Name> key) { return key->hash(); } uint32_t ObjectHashTableShapeBase::Hash(ReadOnlyRoots roots, DirectHandle<Object> key) { return Smi::ToInt(Object::GetHash(*key)); } uint32_t ObjectHashTableShapeBase::HashForObject(ReadOnlyRoots roots, Tagged<Object> other) { return Smi::ToInt(Object::GetHash(other)); } template <typename IsolateT> Handle<NameToIndexHashTable> NameToIndexHashTable::Add( IsolateT* isolate, Handle<NameToIndexHashTable> table, DirectHandle<Name> key, int32_t index) { DCHECK_GE(index, 0); // Validate that the key is absent. SLOW_DCHECK(table->FindEntry(isolate, *key).is_not_found()); // Check whether the dictionary should be extended. table = EnsureCapacity(isolate, table); DisallowGarbageCollection no_gc; Tagged<NameToIndexHashTable> raw_table = *table; // Compute the key object. InternalIndex entry = raw_table->FindInsertionEntry(isolate, key->hash()); raw_table->set(EntryToIndex(entry), *key); raw_table->set(EntryToValueIndex(entry), Smi::FromInt(index)); raw_table->ElementAdded(); return table; } } // namespace internal } // namespace v8 #include "src/objects/object-macros-undef.h" #endif // V8_OBJECTS_HASH_TABLE_INL_H_