// src/objects/ordered-hash-table.cc
template <class Derived, int entrysize>
template <template <typename> typename HandleType>
requires(std::is_convertible_v<HandleType<Derived>, DirectHandle<Derived>>)
HandleType<Derived>::MaybeType OrderedHashTable<Derived, entrysize>::Rehash(
Isolate* isolate, HandleType<Derived> table, int new_capacity) {
DCHECK(!table->IsObsolete());
// 새 테이블을 new_capacity의 크기로 할당
typename HandleType<Derived>::MaybeType new_table_candidate =
Derived::Allocate(isolate, new_capacity,
HeapLayout::InYoungGeneration(*table)
? AllocationType::kYoung
: AllocationType::kOld);
DirectHandle<Derived> new_table;
if (!new_table_candidate.ToHandle(&new_table)) {
return new_table_candidate;
}
// 새 테이블 초기화
int new_buckets = new_table->NumberOfBuckets();
int new_entry = 0;
int removed_holes_index = 0;
DisallowGarbageCollection no_gc;
// 기존 테이블의 엔트리를 모두 순회함
for (InternalIndex old_entry : table->IterateEntries()) {
// 현재 엔트리의 인덱스와 키 값을 가져옴
int old_entry_raw = old_entry.as_int();
Tagged<Object> key = table->KeyAt(old_entry);
// 만약 삭제된 엔트리라면 재배치하지 않고 건너뛴다.
if (IsHashTableHole(key, isolate)) {
table->SetRemovedIndexAt(removed_holes_index++, old_entry_raw);
continue;
}
// 유효한 엔트리를 새 테이블에 복사한다.
// 키로부터 해시값을 구하고, 새 용량에 맞게 계산함
Tagged<Object> hash = Object::GetHash(key);
int bucket = Smi::ToInt(hash) & (new_buckets - 1);
// 체인 헤드를 갱신
Tagged<Object> chain_entry = new_table->get(HashTableStartIndex() + bucket);
new_table->set(HashTableStartIndex() + bucket, Smi::FromInt(new_entry));
// 실제 엔트리 번호를 배열 인덱스로변환
int new_index = new_table->EntryToIndexRaw(new_entry);
int old_index = table->EntryToIndexRaw(old_entry_raw);
// 엔트리 내부 구성요소를 복사
for (int i = 0; i < entrysize; ++i) {
Tagged<Object> value = table->get(old_index + i);
new_table->set(new_index + i, value);
}
// 체인 포인터 연결
new_table->set(new_index + kChainOffset, chain_entry);
++new_entry;
}
DCHECK_EQ(table->NumberOfDeletedElements(), removed_holes_index);
// 요소 개수 동기화
new_table->SetNumberOfElements(table->NumberOfElements());
// 기존 테이블에 연결
if (table->NumberOfBuckets() > 0) {
// Don't try to modify the empty canonical table which lives in RO space.
table->SetNextTable(*new_table);
}
// 결과 반환
return new_table_candidate;
}