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:
parent
6ee715264c
commit
3db0672cc4
@ -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();
|
||||
|
121
src/objects.cc
121
src/objects.cc
@ -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>;
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user