#ifndef V8_OBJECTS_OFF_HEAP_HASH_TABLE_INL_H_
#define V8_OBJECTS_OFF_HEAP_HASH_TABLE_INL_H_
#include "src/objects/off-heap-hash-table.h"
#include "src/objects/compressed-slots-inl.h"
namespace v8 {
namespace internal {
template <typename Derived>
OffHeapHashTableBase<Derived>::OffHeapHashTableBase(int capacity)
: number_of_elements_(0),
number_of_deleted_elements_(0),
capacity_(capacity) {
MemsetTagged(slot(InternalIndex(0)), empty_element(),
capacity * Derived::kEntrySize);
}
template <typename Derived>
void OffHeapHashTableBase<Derived>::RehashInto(PtrComprCageBase cage_base,
Derived* new_table) {
DCHECK_LT(number_of_elements(), new_table->capacity());
DCHECK(new_table->HasSufficientCapacityToAdd(number_of_elements()));
Derived* derived_this = static_cast<Derived*>(this);
for (InternalIndex i : InternalIndex::Range(capacity())) {
Tagged<Object> key = derived_this->GetKey(cage_base, i);
if (!IsKey(key)) continue;
uint32_t hash = Derived::Hash(cage_base, key);
InternalIndex insertion_index =
new_table->FindInsertionEntry(cage_base, hash);
new_table->SetKey(insertion_index, key);
derived_this->CopyEntryExcludingKeyInto(cage_base, i, new_table,
insertion_index);
}
new_table->number_of_elements_ = number_of_elements();
}
template <typename Derived>
inline bool OffHeapHashTableBase<Derived>::ShouldResizeToAdd(
int additional_elements, int* new_capacity) {
DCHECK_NOT_NULL(new_capacity);
int capacity_after_shrinking = ComputeCapacityWithShrink(
capacity_, number_of_elements_ + additional_elements);
if (capacity_after_shrinking < capacity_) {
DCHECK(HasSufficientCapacityToAdd(
capacity_after_shrinking, number_of_elements_, 0, additional_elements));
*new_capacity = capacity_after_shrinking;
return true;
} else if (!HasSufficientCapacityToAdd(additional_elements)) {
*new_capacity = ComputeCapacity(number_of_elements_ + additional_elements);
return true;
} else {
*new_capacity = -1;
return false;
}
}
template <typename Derived>
bool OffHeapHashTableBase<Derived>::HasSufficientCapacityToAdd(
int capacity, int number_of_elements, int number_of_deleted_elements,
int number_of_additional_elements) {
int nof = number_of_elements + number_of_additional_elements;
if ((nof < capacity) &&
((number_of_deleted_elements <= (capacity - nof) / 2))) {
int needed_free = nof / 2;
if (nof + needed_free <= capacity) return true;
}
return false;
}
template <typename Derived>
int OffHeapHashTableBase<Derived>::ComputeCapacity(int at_least_space_for) {
int raw_capacity = at_least_space_for + (at_least_space_for >> 1);
int capacity = base::bits::RoundUpToPowerOfTwo32(raw_capacity);
return std::max(capacity, Derived::kMinCapacity);
}
template <typename Derived>
int OffHeapHashTableBase<Derived>::ComputeCapacityWithShrink(
int current_capacity, int at_least_space_for) {
DCHECK_GE(current_capacity, Derived::kMinCapacity);
if (at_least_space_for > (current_capacity / Derived::kMaxEmptyFactor)) {
return current_capacity;
}
int new_capacity = ComputeCapacity(at_least_space_for);
DCHECK_GE(new_capacity, at_least_space_for);
if (new_capacity < Derived::kMinCapacity) return current_capacity;
return new_capacity;
}
template <typename Derived>
void OffHeapHashTableBase<Derived>::IterateElements(Root root,
RootVisitor* visitor) {
OffHeapObjectSlot first_slot = slot(InternalIndex(0));
OffHeapObjectSlot end_slot = slot(InternalIndex(capacity_));
visitor->VisitCompressedRootPointers(root, nullptr, first_slot, end_slot);
}
template <typename Derived>
template <typename IsolateT, typename FindKey>
InternalIndex OffHeapHashTableBase<Derived>::FindEntry(IsolateT* isolate,
FindKey key,
uint32_t hash) const {
const Derived* derived_this = static_cast<const Derived*>(this);
uint32_t count = 1;
for (InternalIndex entry = FirstProbe(hash, capacity_);;
entry = NextProbe(entry, count++, capacity_)) {
Tagged<Object> element = derived_this->GetKey(isolate, entry);
if (element == empty_element()) return InternalIndex::NotFound();
if (element == deleted_element()) continue;
if (Derived::KeyIsMatch(isolate, key, element)) return entry;
}
}
template <typename Derived>
InternalIndex OffHeapHashTableBase<Derived>::FindInsertionEntry(
PtrComprCageBase cage_base, uint32_t hash) const {
DCHECK(HasSufficientCapacityToAdd(1));
const Derived* derived_this = static_cast<const Derived*>(this);
uint32_t count = 1;
for (InternalIndex entry = FirstProbe(hash, capacity_);;
entry = NextProbe(entry, count++, capacity_)) {
Tagged<Object> element = derived_this->GetKey(cage_base, entry);
if (!IsKey(element)) return entry;
}
}
template <typename Derived>
template <typename IsolateT, typename FindKey>
InternalIndex OffHeapHashTableBase<Derived>::FindEntryOrInsertionEntry(
IsolateT* isolate, FindKey key, uint32_t hash) const {
DCHECK(HasSufficientCapacityToAdd(1));
const Derived* derived_this = static_cast<const Derived*>(this);
InternalIndex insertion_entry = InternalIndex::NotFound();
uint32_t count = 1;
for (InternalIndex entry = FirstProbe(hash, capacity_);;
entry = NextProbe(entry, count++, capacity_)) {
Tagged<Object> element = derived_this->GetKey(isolate, entry);
if (element == empty_element()) {
if (insertion_entry.is_not_found()) return entry;
return insertion_entry;
}
if (element == deleted_element()) {
if (insertion_entry.is_not_found()) insertion_entry = entry;
continue;
}
if (Derived::KeyIsMatch(isolate, key, element)) return entry;
}
}
template <typename Derived>
template <typename Container, size_t OffsetOfElementsInContainer>
void* OffHeapHashTableBase<Derived>::Allocate(int capacity) {
static_assert(OffsetOfElementsInContainer ==
sizeof(Container) - sizeof(Tagged_t));
static_assert(OffsetOfElementsInContainer % kTaggedSize == 0);
return AlignedAllocWithRetry(
sizeof(Container) + GetSizeExcludingHeader(capacity),
std::max(alignof(Container), alignof(void*)));
}
template <typename Derived>
void OffHeapHashTableBase<Derived>::Free(void* table) {
AlignedFree(table);
}
}
}
#endif