Commit 3db0672c authored by Dominik Inführ's avatar Dominik Inführ Committed by Commit Bot

Use EphemeronHashTable as backing store for JSWeakCollection

JSWeakCollection should use EphemeronHashTable as backing store instead of
ObjectHashTable such that the GC can handle these structures differently in
the future.

Bug: chromium:844008
Change-Id: Icc6df60c975a942877e2507ef45e0d235e5f72be
Reviewed-on: https://chromium-review.googlesource.com/1089063
Commit-Queue: Dominik Inführ <dinfuehr@google.com>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53572}
parent 6ee71526
......@@ -1967,7 +1967,7 @@ class WeakCollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
TNode<Smi> CreateIdentityHash(TNode<Object> receiver);
TNode<IntPtrT> EntryMask(TNode<IntPtrT> capacity);
// Builds code that finds the ObjectHashTable entry for a {key} using the
// Builds code that finds the EphemeronHashTable entry for a {key} using the
// comparison code generated by {key_compare}. The key index is returned if
// the {key} is found.
typedef std::function<void(TNode<Object> entry_key, Label* if_same)>
......@@ -1976,12 +1976,13 @@ class WeakCollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
TNode<IntPtrT> entry_mask,
const KeyComparator& key_compare);
// Builds code that finds an ObjectHashTable entry available for a new entry.
// Builds code that finds an EphemeronHashTable entry available for a new
// entry.
TNode<IntPtrT> FindKeyIndexForInsertion(TNode<HeapObject> table,
TNode<IntPtrT> key_hash,
TNode<IntPtrT> entry_mask);
// Builds code that finds the ObjectHashTable entry with key that matches
// Builds code that finds the EphemeronHashTable entry with key that matches
// {key} and returns the entry's key index. If {key} cannot be found, jumps to
// {if_not_found}.
TNode<IntPtrT> FindKeyIndexForKey(TNode<HeapObject> table, TNode<Object> key,
......@@ -2011,13 +2012,13 @@ class WeakCollectionsBuiltinsAssembler : public BaseCollectionsAssembler {
void WeakCollectionsBuiltinsAssembler::AddEntry(
TNode<HeapObject> table, TNode<IntPtrT> key_index, TNode<Object> key,
TNode<Object> value, TNode<IntPtrT> number_of_elements) {
// See ObjectHashTable::AddEntry().
// See EphemeronHashTable::AddEntry().
TNode<IntPtrT> value_index = ValueIndexFromKeyIndex(key_index);
StoreFixedArrayElement(table, key_index, key);
StoreFixedArrayElement(table, value_index, value);
// See HashTableBase::ElementAdded().
StoreFixedArrayElement(table, ObjectHashTable::kNumberOfElementsIndex,
StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
SmiFromIntPtr(number_of_elements), SKIP_WRITE_BARRIER);
}
......@@ -2034,14 +2035,15 @@ TNode<Object> WeakCollectionsBuiltinsAssembler::AllocateTable(
TNode<FixedArray> table =
AllocateFixedArray(HOLEY_ELEMENTS, length, kAllowLargeObjectAllocation);
Heap::RootListIndex map_root_index =
static_cast<Heap::RootListIndex>(ObjectHashTableShape::GetMapRootIndex());
Heap::RootListIndex map_root_index = static_cast<Heap::RootListIndex>(
EphemeronHashTableShape::GetMapRootIndex());
StoreMapNoWriteBarrier(table, map_root_index);
StoreFixedArrayElement(table, ObjectHashTable::kNumberOfElementsIndex,
StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
SmiConstant(0), SKIP_WRITE_BARRIER);
StoreFixedArrayElement(table, ObjectHashTable::kNumberOfDeletedElementsIndex,
StoreFixedArrayElement(table,
EphemeronHashTable::kNumberOfDeletedElementsIndex,
SmiConstant(0), SKIP_WRITE_BARRIER);
StoreFixedArrayElement(table, ObjectHashTable::kCapacityIndex,
StoreFixedArrayElement(table, EphemeronHashTable::kCapacityIndex,
SmiFromIntPtr(capacity), SKIP_WRITE_BARRIER);
TNode<IntPtrT> start = KeyIndexFromEntry(IntPtrConstant(0));
......@@ -2126,22 +2128,22 @@ TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::KeyIndexFromEntry(
// See HashTable::KeyAt().
// (entry * kEntrySize) + kElementsStartIndex + kEntryKeyIndex
return IntPtrAdd(
IntPtrMul(entry, IntPtrConstant(ObjectHashTable::kEntrySize)),
IntPtrConstant(ObjectHashTable::kElementsStartIndex +
ObjectHashTable::kEntryKeyIndex));
IntPtrMul(entry, IntPtrConstant(EphemeronHashTable::kEntrySize)),
IntPtrConstant(EphemeronHashTable::kElementsStartIndex +
EphemeronHashTable::kEntryKeyIndex));
}
TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadNumberOfElements(
TNode<HeapObject> table, int offset) {
TNode<IntPtrT> number_of_elements = SmiUntag(CAST(
LoadFixedArrayElement(table, ObjectHashTable::kNumberOfElementsIndex)));
TNode<IntPtrT> number_of_elements = SmiUntag(CAST(LoadFixedArrayElement(
table, EphemeronHashTable::kNumberOfElementsIndex)));
return IntPtrAdd(number_of_elements, IntPtrConstant(offset));
}
TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadNumberOfDeleted(
TNode<HeapObject> table, int offset) {
TNode<IntPtrT> number_of_deleted = SmiUntag(CAST(LoadFixedArrayElement(
table, ObjectHashTable::kNumberOfDeletedElementsIndex)));
table, EphemeronHashTable::kNumberOfDeletedElementsIndex)));
return IntPtrAdd(number_of_deleted, IntPtrConstant(offset));
}
......@@ -2153,7 +2155,7 @@ TNode<HeapObject> WeakCollectionsBuiltinsAssembler::LoadTable(
TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::LoadTableCapacity(
TNode<HeapObject> table) {
return SmiUntag(
CAST(LoadFixedArrayElement(table, ObjectHashTable::kCapacityIndex)));
CAST(LoadFixedArrayElement(table, EphemeronHashTable::kCapacityIndex)));
}
TNode<Word32T> WeakCollectionsBuiltinsAssembler::InsufficientCapacityToAdd(
......@@ -2177,16 +2179,17 @@ TNode<Word32T> WeakCollectionsBuiltinsAssembler::InsufficientCapacityToAdd(
void WeakCollectionsBuiltinsAssembler::RemoveEntry(
TNode<HeapObject> table, TNode<IntPtrT> key_index,
TNode<IntPtrT> number_of_elements) {
// See ObjectHashTable::RemoveEntry().
// See EphemeronHashTable::RemoveEntry().
TNode<IntPtrT> value_index = ValueIndexFromKeyIndex(key_index);
StoreFixedArrayElement(table, key_index, TheHoleConstant());
StoreFixedArrayElement(table, value_index, TheHoleConstant());
// See HashTableBase::ElementRemoved().
TNode<IntPtrT> number_of_deleted = LoadNumberOfDeleted(table, 1);
StoreFixedArrayElement(table, ObjectHashTable::kNumberOfElementsIndex,
StoreFixedArrayElement(table, EphemeronHashTable::kNumberOfElementsIndex,
SmiFromIntPtr(number_of_elements), SKIP_WRITE_BARRIER);
StoreFixedArrayElement(table, ObjectHashTable::kNumberOfDeletedElementsIndex,
StoreFixedArrayElement(table,
EphemeronHashTable::kNumberOfDeletedElementsIndex,
SmiFromIntPtr(number_of_deleted), SKIP_WRITE_BARRIER);
}
......@@ -2216,8 +2219,8 @@ TNode<Word32T> WeakCollectionsBuiltinsAssembler::ShouldShrink(
TNode<IntPtrT> WeakCollectionsBuiltinsAssembler::ValueIndexFromKeyIndex(
TNode<IntPtrT> key_index) {
return IntPtrAdd(key_index,
IntPtrConstant(ObjectHashTableShape::kEntryValueIndex -
ObjectHashTable::kEntryKeyIndex));
IntPtrConstant(EphemeronHashTableShape::kEntryValueIndex -
EphemeronHashTable::kEntryKeyIndex));
}
TF_BUILTIN(WeakMapConstructor, WeakCollectionsBuiltinsAssembler) {
......@@ -2291,7 +2294,7 @@ TF_BUILTIN(WeakMapHas, WeakCollectionsBuiltinsAssembler) {
}
// Helper that removes the entry with a given key from the backing store
// (ObjectHashTable) of a WeakMap or WeakSet.
// (EphemeronHashTable) of a WeakMap or WeakSet.
TF_BUILTIN(WeakCollectionDelete, WeakCollectionsBuiltinsAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<HeapObject> collection = CAST(Parameter(Descriptor::kCollection));
......@@ -2320,8 +2323,8 @@ TF_BUILTIN(WeakCollectionDelete, WeakCollectionsBuiltinsAssembler) {
SmiTag(hash)));
}
// Helper that sets the key and value to the backing store (ObjectHashTable) of
// a WeakMap or WeakSet.
// Helper that sets the key and value to the backing store (EphemeronHashTable)
// of a WeakMap or WeakSet.
TF_BUILTIN(WeakCollectionSet, WeakCollectionsBuiltinsAssembler) {
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<HeapObject> collection = CAST(Parameter(Descriptor::kCollection));
......
......@@ -1859,16 +1859,17 @@ void MarkCompactCollector::ProcessWeakCollections() {
JSWeakCollection* weak_collection =
reinterpret_cast<JSWeakCollection*>(weak_collection_obj);
DCHECK(non_atomic_marking_state()->IsBlackOrGrey(weak_collection));
if (weak_collection->table()->IsHashTable()) {
ObjectHashTable* table = ObjectHashTable::cast(weak_collection->table());
if (weak_collection->table()->IsEphemeronHashTable()) {
EphemeronHashTable* table =
EphemeronHashTable::cast(weak_collection->table());
for (int i = 0; i < table->Capacity(); i++) {
HeapObject* heap_object = HeapObject::cast(table->KeyAt(i));
if (non_atomic_marking_state()->IsBlackOrGrey(heap_object)) {
Object** key_slot =
table->RawFieldOfElementAt(ObjectHashTable::EntryToIndex(i));
table->RawFieldOfElementAt(EphemeronHashTable::EntryToIndex(i));
RecordSlot(table, key_slot, *key_slot);
Object** value_slot =
table->RawFieldOfElementAt(ObjectHashTable::EntryToValueIndex(i));
Object** value_slot = table->RawFieldOfElementAt(
EphemeronHashTable::EntryToValueIndex(i));
if (V8_UNLIKELY(FLAG_track_retaining_path) &&
(*value_slot)->IsHeapObject()) {
heap()->AddEphemeralRetainer(heap_object,
......@@ -1889,8 +1890,9 @@ void MarkCompactCollector::ClearWeakCollections() {
JSWeakCollection* weak_collection =
reinterpret_cast<JSWeakCollection*>(weak_collection_obj);
DCHECK(non_atomic_marking_state()->IsBlackOrGrey(weak_collection));
if (weak_collection->table()->IsHashTable()) {
ObjectHashTable* table = ObjectHashTable::cast(weak_collection->table());
if (weak_collection->table()->IsEphemeronHashTable()) {
EphemeronHashTable* table =
EphemeronHashTable::cast(weak_collection->table());
for (int i = 0; i < table->Capacity(); i++) {
HeapObject* key = HeapObject::cast(table->KeyAt(i));
if (!non_atomic_marking_state()->IsBlackOrGrey(key)) {
......
......@@ -505,6 +505,8 @@ bool HeapObject::IsMapCache() const { return IsHashTable(); }
bool HeapObject::IsObjectHashTable() const { return IsHashTable(); }
bool HeapObject::IsEphemeronHashTable() const { return IsHashTable(); }
bool HeapObject::IsOrderedHashSet() const {
return map() == GetHeap()->ordered_hash_set_map();
}
......@@ -597,6 +599,7 @@ CAST_ACCESSOR(BoilerplateDescription)
CAST_ACCESSOR(Cell)
CAST_ACCESSOR(ConstantElementsPair)
CAST_ACCESSOR(DescriptorArray)
CAST_ACCESSOR(EphemeronHashTable)
CAST_ACCESSOR(EnumCache)
CAST_ACCESSOR(FeedbackCell)
CAST_ACCESSOR(Foreign)
......@@ -3311,10 +3314,6 @@ Handle<Object> ObjectHashTableShape::AsHandle(Isolate* isolate,
return key;
}
Handle<ObjectHashTable> ObjectHashTable::Shrink(Handle<ObjectHashTable> table) {
return DerivedHashTable::Shrink(table);
}
Relocatable::Relocatable(Isolate* isolate) {
isolate_ = isolate;
prev_ = isolate->relocatable_top();
......
......@@ -18000,23 +18000,24 @@ Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) {
return isolate->heap()->undefined_value();
}
Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
template <typename Derived, typename Shape>
Object* ObjectHashTableBase<Derived, Shape>::Lookup(Isolate* isolate,
Handle<Object> key,
int32_t hash) {
DisallowHeapAllocation no_gc;
DCHECK(IsKey(isolate, *key));
DCHECK(this->IsKey(isolate, *key));
int entry = FindEntry(isolate, key, hash);
int entry = this->FindEntry(isolate, key, hash);
if (entry == kNotFound) return isolate->heap()->the_hole_value();
return get(EntryToIndex(entry) + 1);
return this->get(Derived::EntryToIndex(entry) + 1);
}
Object* ObjectHashTable::Lookup(Handle<Object> key) {
template <typename Derived, typename Shape>
Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key) {
DisallowHeapAllocation no_gc;
Isolate* isolate = GetIsolate();
DCHECK(IsKey(isolate, *key));
Isolate* isolate = this->GetIsolate();
DCHECK(this->IsKey(isolate, *key));
// If the object does not have an identity hash, it was never used as a key.
Object* hash = key->GetHash();
......@@ -18026,16 +18027,19 @@ Object* ObjectHashTable::Lookup(Handle<Object> key) {
return Lookup(isolate, key, Smi::ToInt(hash));
}
Object* ObjectHashTable::ValueAt(int entry) {
return get(EntryToValueIndex(entry));
template <typename Derived, typename Shape>
Object* ObjectHashTableBase<Derived, Shape>::Lookup(Handle<Object> key,
int32_t hash) {
return Lookup(this->GetIsolate(), key, hash);
}
Object* ObjectHashTable::Lookup(Handle<Object> key, int32_t hash) {
return Lookup(GetIsolate(), key, hash);
template <typename Derived, typename Shape>
Object* ObjectHashTableBase<Derived, Shape>::ValueAt(int entry) {
return this->get(EntryToValueIndex(entry));
}
Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
template <typename Derived, typename Shape>
Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
Handle<Object> key,
Handle<Object> value) {
Isolate* isolate = table->GetIsolate();
......@@ -18045,11 +18049,11 @@ Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
// Make sure the key object has an identity hash code.
int32_t hash = key->GetOrCreateHash(isolate)->value();
return Put(table, key, value, hash);
return ObjectHashTableBase<Derived, Shape>::Put(table, key, value, hash);
}
Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
template <typename Derived, typename Shape>
Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
Handle<Object> key,
Handle<Object> value,
int32_t hash) {
......@@ -18061,7 +18065,7 @@ Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
// Key is already in table, just overwrite value.
if (entry != kNotFound) {
table->set(EntryToIndex(entry) + 1, *value);
table->set(Derived::EntryToIndex(entry) + 1, *value);
return table;
}
......@@ -18086,15 +18090,14 @@ Handle<ObjectHashTable> ObjectHashTable::Put(Handle<ObjectHashTable> table,
}
// Check whether the hash table should be extended.
table = EnsureCapacity(table, 1);
table = Derived::EnsureCapacity(table, 1);
table->AddEntry(table->FindInsertionEntry(hash), *key, *value);
return table;
}
Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
Handle<Object> key,
bool* was_present) {
template <typename Derived, typename Shape>
Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
Handle<Derived> table, Handle<Object> key, bool* was_present) {
DCHECK(table->IsKey(table->GetIsolate(), *key));
Object* hash = key->GetHash();
......@@ -18106,10 +18109,9 @@ Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
return Remove(table, key, was_present, Smi::ToInt(hash));
}
Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
Handle<Object> key,
bool* was_present,
template <typename Derived, typename Shape>
Handle<Derived> ObjectHashTableBase<Derived, Shape>::Remove(
Handle<Derived> table, Handle<Object> key, bool* was_present,
int32_t hash) {
Isolate* isolate = table->GetIsolate();
DCHECK(table->IsKey(isolate, *key));
......@@ -18122,21 +18124,22 @@ Handle<ObjectHashTable> ObjectHashTable::Remove(Handle<ObjectHashTable> table,
*was_present = true;
table->RemoveEntry(entry);
return Shrink(table);
return Derived::Shrink(table);
}
void ObjectHashTable::AddEntry(int entry, Object* key, Object* value) {
set(EntryToIndex(entry), key);
set(EntryToIndex(entry) + 1, value);
ElementAdded();
template <typename Derived, typename Shape>
void ObjectHashTableBase<Derived, Shape>::AddEntry(int entry, Object* key,
Object* value) {
this->set(Derived::EntryToIndex(entry), key);
this->set(Derived::EntryToIndex(entry) + 1, value);
this->ElementAdded();
}
void ObjectHashTable::RemoveEntry(int entry) {
set_the_hole(EntryToIndex(entry));
set_the_hole(EntryToIndex(entry) + 1);
ElementRemoved();
template <typename Derived, typename Shape>
void ObjectHashTableBase<Derived, Shape>::RemoveEntry(int entry) {
this->set_the_hole(Derived::EntryToIndex(entry));
this->set_the_hole(Derived::EntryToIndex(entry) + 1);
this->ElementRemoved();
}
......@@ -18168,7 +18171,7 @@ void JSMap::Clear(Handle<JSMap> map) {
void JSWeakCollection::Initialize(Handle<JSWeakCollection> weak_collection,
Isolate* isolate) {
Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 0);
weak_collection->set_table(*table);
}
......@@ -18177,11 +18180,11 @@ void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
Handle<Object> key, Handle<Object> value,
int32_t hash) {
DCHECK(key->IsJSReceiver() || key->IsSymbol());
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
Handle<EphemeronHashTable> table(
EphemeronHashTable::cast(weak_collection->table()));
DCHECK(table->IsKey(table->GetIsolate(), *key));
Handle<ObjectHashTable> new_table =
ObjectHashTable::Put(table, key, value, hash);
Handle<EphemeronHashTable> new_table =
EphemeronHashTable::Put(table, key, value, hash);
weak_collection->set_table(*new_table);
if (*table != *new_table) {
// Zap the old table since we didn't record slots for its elements.
......@@ -18193,12 +18196,12 @@ void JSWeakCollection::Set(Handle<JSWeakCollection> weak_collection,
bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
Handle<Object> key, int32_t hash) {
DCHECK(key->IsJSReceiver() || key->IsSymbol());
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
Handle<EphemeronHashTable> table(
EphemeronHashTable::cast(weak_collection->table()));
DCHECK(table->IsKey(table->GetIsolate(), *key));
bool was_present = false;
Handle<ObjectHashTable> new_table =
ObjectHashTable::Remove(table, key, &was_present, hash);
Handle<EphemeronHashTable> new_table =
EphemeronHashTable::Remove(table, key, &was_present, hash);
weak_collection->set_table(*new_table);
if (*table != *new_table) {
// Zap the old table since we didn't record slots for its elements.
......@@ -18210,7 +18213,7 @@ bool JSWeakCollection::Delete(Handle<JSWeakCollection> weak_collection,
Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
int max_entries) {
Isolate* isolate = holder->GetIsolate();
Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
Handle<EphemeronHashTable> table(EphemeronHashTable::cast(holder->table()));
if (max_entries == 0 || max_entries > table->NumberOfElements()) {
max_entries = table->NumberOfElements();
}
......@@ -18870,6 +18873,12 @@ template class HashTable<CompilationCacheTable, CompilationCacheShape>;
template class HashTable<ObjectHashTable, ObjectHashTableShape>;
template class HashTable<EphemeronHashTable, EphemeronHashTableShape>;
template class ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape>;
template class ObjectHashTableBase<EphemeronHashTable, EphemeronHashTableShape>;
template class Dictionary<NameDictionary, NameDictionaryShape>;
template class Dictionary<GlobalDictionary, GlobalDictionaryShape>;
......
......@@ -1054,6 +1054,7 @@ template <class C> inline bool Is(Object* obj);
V(DeoptimizationData) \
V(DependentCode) \
V(DescriptorArray) \
V(EphemeronHashTable) \
V(EnumCache) \
V(External) \
V(ExternalOneByteString) \
......
......@@ -269,19 +269,9 @@ class ObjectHashTableShape : public BaseShape<Handle<Object>> {
static const bool kNeedsHoleCheck = false;
};
// ObjectHashTable maps keys that are arbitrary objects to object values by
// using the identity hash of the key for hashing purposes.
class ObjectHashTable
: public HashTable<ObjectHashTable, ObjectHashTableShape> {
typedef HashTable<ObjectHashTable, ObjectHashTableShape> DerivedHashTable;
template <typename Derived, typename Shape>
class ObjectHashTableBase : public HashTable<Derived, Shape> {
public:
DECL_CAST(ObjectHashTable)
// Attempt to shrink hash table after removal of key.
V8_WARN_UNUSED_RESULT static inline Handle<ObjectHashTable> Shrink(
Handle<ObjectHashTable> table);
// Looks up the value associated with the given key. The hole value is
// returned in case the key is not present.
Object* Lookup(Handle<Object> key);
......@@ -292,31 +282,51 @@ class ObjectHashTable
Object* ValueAt(int entry);
// Adds (or overwrites) the value associated with the given key.
static Handle<ObjectHashTable> Put(Handle<ObjectHashTable> table,
Handle<Object> key, Handle<Object> value);
static Handle<ObjectHashTable> Put(Handle<ObjectHashTable> table,
Handle<Object> key, Handle<Object> value,
int32_t hash);
static Handle<Derived> Put(Handle<Derived> table, Handle<Object> key,
Handle<Object> value);
static Handle<Derived> Put(Handle<Derived> table, Handle<Object> key,
Handle<Object> value, int32_t hash);
// Returns an ObjectHashTable (possibly |table|) where |key| has been removed.
static Handle<ObjectHashTable> Remove(Handle<ObjectHashTable> table,
Handle<Object> key, bool* was_present);
static Handle<ObjectHashTable> Remove(Handle<ObjectHashTable> table,
Handle<Object> key, bool* was_present,
int32_t hash);
static Handle<Derived> Remove(Handle<Derived> table, Handle<Object> key,
bool* was_present);
static Handle<Derived> Remove(Handle<Derived> table, Handle<Object> key,
bool* was_present, int32_t hash);
// Returns the index to the value of an entry.
static inline int EntryToValueIndex(int entry) {
return EntryToIndex(entry) + ObjectHashTableShape::kEntryValueIndex;
return HashTable<Derived, Shape>::EntryToIndex(entry) +
Shape::kEntryValueIndex;
}
protected:
friend class MarkCompactCollector;
void AddEntry(int entry, Object* key, Object* value);
void RemoveEntry(int entry);
};
// ObjectHashTable maps keys that are arbitrary objects to object values by
// using the identity hash of the key for hashing purposes.
class ObjectHashTable
: public ObjectHashTableBase<ObjectHashTable, ObjectHashTableShape> {
public:
DECL_CAST(ObjectHashTable)
};
typedef ObjectHashTableShape EphemeronHashTableShape;
// EphemeronHashTable is similar to ObjectHashTable but gets special treatment
// by the GC. The GC treats its entries as ephemerons: both key and value are
// weak references, however if the key is strongly reachable its corresponding
// value is also kept alive.
class EphemeronHashTable
: public ObjectHashTableBase<EphemeronHashTable, EphemeronHashTableShape> {
public:
DECL_CAST(EphemeronHashTable)
protected:
friend class MarkCompactCollector;
};
class ObjectHashSetShape : public ObjectHashTableShape {
public:
static const int kPrefixSize = 0;
......
......@@ -1038,7 +1038,7 @@ void V8HeapExplorer::ExtractJSCollectionReferences(int entry,
void V8HeapExplorer::ExtractJSWeakCollectionReferences(int entry,
JSWeakCollection* obj) {
if (obj->table()->IsHashTable()) {
ObjectHashTable* table = ObjectHashTable::cast(obj->table());
EphemeronHashTable* table = EphemeronHashTable::cast(obj->table());
TagFixedArraySubType(table, JS_WEAK_COLLECTION_SUB_TYPE);
}
SetInternalReference(obj, entry, "table", obj->table(),
......@@ -1361,11 +1361,11 @@ void V8HeapExplorer::ExtractFixedArrayReferences(int entry, FixedArray* array) {
}
switch (it->second) {
case JS_WEAK_COLLECTION_SUB_TYPE: {
ObjectHashTable* table = ObjectHashTable::cast(array);
EphemeronHashTable* table = EphemeronHashTable::cast(array);
for (int i = 0, capacity = table->Capacity(); i < capacity; ++i) {
int key_index =
ObjectHashTable::EntryToIndex(i) + ObjectHashTable::kEntryKeyIndex;
int value_index = ObjectHashTable::EntryToValueIndex(i);
int key_index = EphemeronHashTable::EntryToIndex(i) +
EphemeronHashTable::kEntryKeyIndex;
int value_index = EphemeronHashTable::EntryToValueIndex(i);
Object* key = table->get(key_index);
Object* value = table->get(value_index);
SetWeakReference(table, entry, key_index, key,
......
......@@ -98,9 +98,9 @@ RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
#ifdef DEBUG
DCHECK(key->IsJSReceiver());
DCHECK(ObjectHashTableShape::IsLive(isolate, *key));
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
DCHECK(EphemeronHashTableShape::IsLive(isolate, *key));
Handle<EphemeronHashTable> table(
EphemeronHashTable::cast(weak_collection->table()));
// Should only be called when shrinking the table is necessary. See
// HashTable::Shrink().
DCHECK(table->NumberOfElements() - 1 <= (table->Capacity() >> 2) &&
......@@ -130,11 +130,11 @@ RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
#ifdef DEBUG
DCHECK(key->IsJSReceiver());
DCHECK(ObjectHashTableShape::IsLive(isolate, *key));
Handle<ObjectHashTable> table(
ObjectHashTable::cast(weak_collection->table()));
DCHECK(EphemeronHashTableShape::IsLive(isolate, *key));
Handle<EphemeronHashTable> table(
EphemeronHashTable::cast(weak_collection->table()));
// Should only be called when rehashing or resizing the table is necessary.
// See ObjectHashTable::Put() and HashTable::HasSufficientCapacityToAdd().
// See EphemeronHashTable::Put() and HashTable::HasSufficientCapacityToAdd().
DCHECK((table->NumberOfDeletedElements() << 1) > table->NumberOfElements() ||
!table->HasSufficientCapacityToAdd(1));
#endif
......
......@@ -85,14 +85,14 @@ TEST(Weakness) {
int32_t object_hash = object->GetOrCreateHash(isolate)->value();
JSWeakCollection::Set(weakmap, object, smi, object_hash);
}
CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(2, EphemeronHashTable::cast(weakmap->table())->NumberOfElements());
// Force a full GC.
CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(0, NumberOfWeakCalls);
CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(2, EphemeronHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(
0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
0, EphemeronHashTable::cast(weakmap->table())->NumberOfDeletedElements());
// Make the global reference to the key weak.
std::pair<Handle<Object>*, int> handle_and_id(&key, 1234);
......@@ -103,9 +103,9 @@ TEST(Weakness) {
CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(1, NumberOfWeakCalls);
CHECK_EQ(0, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(2,
ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
CHECK_EQ(0, EphemeronHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(
2, EphemeronHashTable::cast(weakmap->table())->NumberOfDeletedElements());
}
......@@ -117,7 +117,7 @@ TEST(Shrinking) {
Handle<JSWeakMap> weakmap = isolate->factory()->NewJSWeakMap();
// Check initial capacity.
CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->Capacity());
CHECK_EQ(32, EphemeronHashTable::cast(weakmap->table())->Capacity());
// Fill up weak map to trigger capacity change.
{
......@@ -132,19 +132,20 @@ TEST(Shrinking) {
}
// Check increased capacity.
CHECK_EQ(128, ObjectHashTable::cast(weakmap->table())->Capacity());
CHECK_EQ(128, EphemeronHashTable::cast(weakmap->table())->Capacity());
// Force a full GC.
CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(32, EphemeronHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(
0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
0, EphemeronHashTable::cast(weakmap->table())->NumberOfDeletedElements());
CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(0, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(0, EphemeronHashTable::cast(weakmap->table())->NumberOfElements());
CHECK_EQ(
32, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
32,
EphemeronHashTable::cast(weakmap->table())->NumberOfDeletedElements());
// Check shrunk capacity.
CHECK_EQ(32, ObjectHashTable::cast(weakmap->table())->Capacity());
CHECK_EQ(32, EphemeronHashTable::cast(weakmap->table())->Capacity());
}
......
......@@ -53,7 +53,7 @@ static Handle<JSWeakSet> AllocateJSWeakSet(Isolate* isolate) {
// Do not leak handles for the hash table, it would make entries strong.
{
HandleScope scope(isolate);
Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 1);
Handle<EphemeronHashTable> table = EphemeronHashTable::New(isolate, 1);
weakset->set_table(*table);
}
return weakset;
......@@ -96,14 +96,14 @@ TEST(WeakSet_Weakness) {
int32_t hash = key->GetOrCreateHash(isolate)->value();
JSWeakCollection::Set(weakset, key, smi, hash);
}
CHECK_EQ(1, ObjectHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(1, EphemeronHashTable::cast(weakset->table())->NumberOfElements());
// Force a full GC.
CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(0, NumberOfWeakCalls);
CHECK_EQ(1, ObjectHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(1, EphemeronHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(
0, ObjectHashTable::cast(weakset->table())->NumberOfDeletedElements());
0, EphemeronHashTable::cast(weakset->table())->NumberOfDeletedElements());
// Make the global reference to the key weak.
std::pair<Handle<Object>*, int> handle_and_id(&key, 1234);
......@@ -114,9 +114,9 @@ TEST(WeakSet_Weakness) {
CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(1, NumberOfWeakCalls);
CHECK_EQ(0, ObjectHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(0, EphemeronHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(
1, ObjectHashTable::cast(weakset->table())->NumberOfDeletedElements());
1, EphemeronHashTable::cast(weakset->table())->NumberOfDeletedElements());
}
......@@ -128,7 +128,7 @@ TEST(WeakSet_Shrinking) {
Handle<JSWeakSet> weakset = AllocateJSWeakSet(isolate);
// Check initial capacity.
CHECK_EQ(32, ObjectHashTable::cast(weakset->table())->Capacity());
CHECK_EQ(32, EphemeronHashTable::cast(weakset->table())->Capacity());
// Fill up weak set to trigger capacity change.
{
......@@ -143,19 +143,20 @@ TEST(WeakSet_Shrinking) {
}
// Check increased capacity.
CHECK_EQ(128, ObjectHashTable::cast(weakset->table())->Capacity());
CHECK_EQ(128, EphemeronHashTable::cast(weakset->table())->Capacity());
// Force a full GC.
CHECK_EQ(32, ObjectHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(32, EphemeronHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(
0, ObjectHashTable::cast(weakset->table())->NumberOfDeletedElements());
0, EphemeronHashTable::cast(weakset->table())->NumberOfDeletedElements());
CcTest::CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
CHECK_EQ(0, ObjectHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(0, EphemeronHashTable::cast(weakset->table())->NumberOfElements());
CHECK_EQ(
32, ObjectHashTable::cast(weakset->table())->NumberOfDeletedElements());
32,
EphemeronHashTable::cast(weakset->table())->NumberOfDeletedElements());
// Check shrunk capacity.
CHECK_EQ(32, ObjectHashTable::cast(weakset->table())->Capacity());
CHECK_EQ(32, EphemeronHashTable::cast(weakset->table())->Capacity());
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment