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: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53572}
This commit is contained in:
Dominik Inführ 2018-06-07 07:57:16 +02:00 committed by Commit Bot
parent 6ee715264c
commit 3db0672cc4
10 changed files with 181 additions and 155 deletions

View File

@ -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));

View File

@ -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)) {

View File

@ -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();

View File

@ -18000,23 +18000,24 @@ Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) {
return isolate->heap()->undefined_value();
}
Object* ObjectHashTable::Lookup(Isolate* isolate, Handle<Object> key,
int32_t hash) {
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,18 +18027,21 @@ 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,
Handle<Object> key,
Handle<Object> value) {
template <typename Derived, typename Shape>
Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
Handle<Object> key,
Handle<Object> value) {
Isolate* isolate = table->GetIsolate();
DCHECK(table->IsKey(isolate, *key));
DCHECK(!value->IsTheHole(isolate));
@ -18045,14 +18049,14 @@ 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,
Handle<Object> key,
Handle<Object> value,
int32_t hash) {
template <typename Derived, typename Shape>
Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
Handle<Object> key,
Handle<Object> value,
int32_t hash) {
Isolate* isolate = table->GetIsolate();
DCHECK(table->IsKey(isolate, *key));
DCHECK(!value->IsTheHole(isolate));
@ -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,11 +18109,10 @@ 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,
int32_t hash) {
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>;

View File

@ -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) \

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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());
}

View File

@ -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());
}