[dict] Add more useful methods

Change-Id: I1bed84a7aa2004f13a51cc60c4d6596b21968ba8
Bug: v8:6443, v8:7569
Reviewed-on: https://chromium-review.googlesource.com/c/1387995
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58602}
This commit is contained in:
Sathya Gunasekaran 2019-01-07 10:32:24 -08:00 committed by Commit Bot
parent 5d40e9de86
commit 0bd4e348e0
5 changed files with 446 additions and 27 deletions

View File

@ -542,8 +542,16 @@ Handle<FrameArray> Factory::NewFrameArray(int number_of_frames,
template <typename T>
Handle<T> Factory::AllocateSmallOrderedHashTable(Handle<Map> map, int capacity,
PretenureFlag pretenure) {
DCHECK_LE(0, capacity);
CHECK_LE(capacity, T::kMaxCapacity);
// Capacity must be a power of two, since we depend on being able
// to divide and multiple by 2 (kLoadFactor) to derive capacity
// from number of buckets. If we decide to change kLoadFactor
// to something other than 2, capacity should be stored as another
// field of this object.
DCHECK_EQ(T::kLoadFactor, 2);
capacity = base::bits::RoundUpToPowerOfTwo32(Max(T::kMinCapacity, capacity));
capacity = Min(capacity, T::kMaxCapacity);
DCHECK_LT(0, capacity);
DCHECK_EQ(0, capacity % T::kLoadFactor);
int size = T::SizeFor(capacity);

View File

@ -394,13 +394,13 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
JSDataView::cast(*this)->JSDataViewVerify(isolate);
break;
case SMALL_ORDERED_HASH_SET_TYPE:
SmallOrderedHashSet::cast(*this)->SmallOrderedHashTableVerify(isolate);
SmallOrderedHashSet::cast(*this)->SmallOrderedHashSetVerify(isolate);
break;
case SMALL_ORDERED_HASH_MAP_TYPE:
SmallOrderedHashMap::cast(*this)->SmallOrderedHashTableVerify(isolate);
SmallOrderedHashMap::cast(*this)->SmallOrderedHashMapVerify(isolate);
break;
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
SmallOrderedNameDictionary::cast(*this)->SmallOrderedHashTableVerify(
SmallOrderedNameDictionary::cast(*this)->SmallOrderedNameDictionaryVerify(
isolate);
break;
case CODE_DATA_CONTAINER_TYPE:
@ -1515,14 +1515,6 @@ void SmallOrderedHashTable<Derived>::SmallOrderedHashTableVerify(
}
}
for (int entry = NumberOfElements(); entry < NumberOfDeletedElements();
entry++) {
for (int offset = 0; offset < Derived::kEntrySize; offset++) {
Object val = GetDataEntry(entry, offset);
CHECK(val->IsTheHole(isolate));
}
}
for (int entry = NumberOfElements() + NumberOfDeletedElements();
entry < Capacity(); entry++) {
for (int offset = 0; offset < Derived::kEntrySize; offset++) {
@ -1531,13 +1523,43 @@ void SmallOrderedHashTable<Derived>::SmallOrderedHashTableVerify(
}
}
}
void SmallOrderedHashMap::SmallOrderedHashMapVerify(Isolate* isolate) {
SmallOrderedHashTable<SmallOrderedHashMap>::SmallOrderedHashTableVerify(
isolate);
for (int entry = NumberOfElements(); entry < NumberOfDeletedElements();
entry++) {
for (int offset = 0; offset < kEntrySize; offset++) {
Object val = GetDataEntry(entry, offset);
CHECK(val->IsTheHole(isolate));
}
}
}
template void SmallOrderedHashTable<
SmallOrderedHashMap>::SmallOrderedHashTableVerify(Isolate* isolate);
template void SmallOrderedHashTable<
SmallOrderedHashSet>::SmallOrderedHashTableVerify(Isolate* isolate);
template void SmallOrderedHashTable<
SmallOrderedNameDictionary>::SmallOrderedHashTableVerify(Isolate* isolate);
void SmallOrderedHashSet::SmallOrderedHashSetVerify(Isolate* isolate) {
SmallOrderedHashTable<SmallOrderedHashSet>::SmallOrderedHashTableVerify(
isolate);
for (int entry = NumberOfElements(); entry < NumberOfDeletedElements();
entry++) {
for (int offset = 0; offset < kEntrySize; offset++) {
Object val = GetDataEntry(entry, offset);
CHECK(val->IsTheHole(isolate));
}
}
}
void SmallOrderedNameDictionary::SmallOrderedNameDictionaryVerify(
Isolate* isolate) {
SmallOrderedHashTable<
SmallOrderedNameDictionary>::SmallOrderedHashTableVerify(isolate);
for (int entry = NumberOfElements(); entry < NumberOfDeletedElements();
entry++) {
for (int offset = 0; offset < kEntrySize; offset++) {
Object val = GetDataEntry(entry, offset);
CHECK(val->IsTheHole(isolate) ||
(PropertyDetails::Empty().AsSmi() == Smi::cast(val)));
}
}
}
void JSRegExp::JSRegExpVerify(Isolate* isolate) {
JSObjectVerify(isolate);

View File

@ -368,6 +368,37 @@ Handle<OrderedNameDictionary> OrderedNameDictionary::Add(
return table;
}
void OrderedNameDictionary::SetEntry(Isolate* isolate, int entry, Object key,
Object value, PropertyDetails details) {
DisallowHeapAllocation gc;
DCHECK_IMPLIES(!key->IsName(), key->IsTheHole(isolate));
DisallowHeapAllocation no_gc;
int index = EntryToIndex(entry);
this->set(index, key);
this->set(index + kValueOffset, value);
// TODO(gsathya): Optimize how PropertyDetails are stored in this
// dictionary to save memory (by reusing padding?) and performance
// (by not doing the Smi conversion).
this->set(index + kPropertyDetailsOffset, details.AsSmi());
}
Handle<OrderedNameDictionary> OrderedNameDictionary::DeleteEntry(
Isolate* isolate, Handle<OrderedNameDictionary> table, int entry) {
DCHECK_NE(entry, kNotFound);
Object hole = ReadOnlyRoots(isolate).the_hole_value();
PropertyDetails details = PropertyDetails::Empty();
table->SetEntry(isolate, entry, hole, hole, details);
int nof = table->NumberOfElements();
table->SetNumberOfElements(nof - 1);
int nod = table->NumberOfDeletedElements();
table->SetNumberOfDeletedElements(nod + 1);
return Shrink(isolate, table);
}
Handle<OrderedHashSet> OrderedHashSet::Allocate(Isolate* isolate, int capacity,
PretenureFlag pretenure) {
return OrderedHashTable<OrderedHashSet, 1>::Allocate(isolate, capacity,
@ -431,6 +462,10 @@ template bool OrderedHashTable<OrderedHashMap, 2>::Delete(Isolate* isolate,
template int OrderedHashTable<OrderedHashMap, 2>::FindEntry(Isolate* isolate,
Object key);
template Handle<OrderedNameDictionary>
OrderedHashTable<OrderedNameDictionary, 3>::Shrink(
Isolate* isolate, Handle<OrderedNameDictionary> table);
template Handle<OrderedNameDictionary>
OrderedHashTable<OrderedNameDictionary, 3>::EnsureGrowable(
Isolate* isolate, Handle<OrderedNameDictionary> table);
@ -628,6 +663,19 @@ MaybeHandle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Add(
return table;
}
void SmallOrderedNameDictionary::SetEntry(Isolate* isolate, int entry,
Object key, Object value,
PropertyDetails details) {
DCHECK_IMPLIES(!key->IsName(), key->IsTheHole(isolate));
SetDataEntry(entry, SmallOrderedNameDictionary::kValueIndex, value);
SetDataEntry(entry, SmallOrderedNameDictionary::kKeyIndex, key);
// TODO(gsathya): PropertyDetails should be stored as part of the
// data table to save more memory.
SetDataEntry(entry, SmallOrderedNameDictionary::kPropertyDetailsIndex,
details.AsSmi());
}
template <class Derived>
bool SmallOrderedHashTable<Derived>::HasKey(Isolate* isolate,
Handle<Object> key) {
@ -656,6 +704,23 @@ bool SmallOrderedHashTable<Derived>::Delete(Isolate* isolate, Derived table,
return true;
}
Handle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::DeleteEntry(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table, int entry) {
DCHECK_NE(entry, kNotFound);
{
DisallowHeapAllocation no_gc;
Object hole = ReadOnlyRoots(isolate).the_hole_value();
PropertyDetails details = PropertyDetails::Empty();
table->SetEntry(isolate, entry, hole, hole, details);
int nof = table->NumberOfElements();
table->SetNumberOfElements(nof - 1);
int nod = table->NumberOfDeletedElements();
table->SetNumberOfDeletedElements(nod + 1);
}
return Shrink(isolate, table);
}
template <class Derived>
Handle<Derived> SmallOrderedHashTable<Derived>::Rehash(Isolate* isolate,
Handle<Derived> table,
@ -716,6 +781,15 @@ Handle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Rehash(
return new_table;
}
template <class Derived>
Handle<Derived> SmallOrderedHashTable<Derived>::Shrink(Isolate* isolate,
Handle<Derived> table) {
int nof = table->NumberOfElements();
int capacity = table->Capacity();
if (nof >= (capacity >> 2)) return table;
return Derived::Rehash(isolate, table, capacity / 2);
}
template <class Derived>
MaybeHandle<Derived> SmallOrderedHashTable<Derived>::Grow(
Isolate* isolate, Handle<Derived> table) {
@ -765,6 +839,9 @@ template bool SmallOrderedHashTable<SmallOrderedHashSet>::HasKey(
template Handle<SmallOrderedHashSet>
SmallOrderedHashTable<SmallOrderedHashSet>::Rehash(
Isolate* isolate, Handle<SmallOrderedHashSet> table, int new_capacity);
template Handle<SmallOrderedHashSet>
SmallOrderedHashTable<SmallOrderedHashSet>::Shrink(
Isolate* isolate, Handle<SmallOrderedHashSet> table);
template MaybeHandle<SmallOrderedHashSet>
SmallOrderedHashTable<SmallOrderedHashSet>::Grow(
Isolate* isolate, Handle<SmallOrderedHashSet> table);
@ -776,6 +853,9 @@ template bool SmallOrderedHashTable<SmallOrderedHashMap>::HasKey(
template Handle<SmallOrderedHashMap>
SmallOrderedHashTable<SmallOrderedHashMap>::Rehash(
Isolate* isolate, Handle<SmallOrderedHashMap> table, int new_capacity);
template Handle<SmallOrderedHashMap>
SmallOrderedHashTable<SmallOrderedHashMap>::Shrink(
Isolate* isolate, Handle<SmallOrderedHashMap> table);
template MaybeHandle<SmallOrderedHashMap>
SmallOrderedHashTable<SmallOrderedHashMap>::Grow(
Isolate* isolate, Handle<SmallOrderedHashMap> table);
@ -789,6 +869,9 @@ template bool SmallOrderedHashTable<SmallOrderedHashSet>::Delete(
template void SmallOrderedHashTable<SmallOrderedNameDictionary>::Initialize(
Isolate* isolate, int capacity);
template Handle<SmallOrderedNameDictionary>
SmallOrderedHashTable<SmallOrderedNameDictionary>::Shrink(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table);
template <class SmallTable, class LargeTable>
Handle<HeapObject> OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(
@ -969,8 +1052,23 @@ Handle<HeapObject> OrderedNameDictionaryHandler::Add(Isolate* isolate,
isolate, Handle<OrderedNameDictionary>::cast(table), key, value, details);
}
void OrderedNameDictionaryHandler::SetEntry(Isolate* isolate, HeapObject table,
int entry, Object key, Object value,
PropertyDetails details) {
DisallowHeapAllocation no_gc;
if (table->IsSmallOrderedNameDictionary()) {
return SmallOrderedNameDictionary::cast(table)->SetEntry(
isolate, entry, key, value, details);
}
DCHECK(table->IsOrderedNameDictionary());
return OrderedNameDictionary::cast(table)->SetEntry(isolate, entry, key,
value, details);
}
int OrderedNameDictionaryHandler::FindEntry(Isolate* isolate, HeapObject table,
Object key) {
Name key) {
DisallowHeapAllocation no_gc;
if (table->IsSmallOrderedNameDictionary()) {
int entry =
SmallOrderedNameDictionary::cast(table)->FindEntry(isolate, key);
@ -1044,6 +1142,57 @@ void OrderedNameDictionaryHandler::SetHash(HeapObject table, int hash) {
OrderedNameDictionary::cast(table)->SetHash(hash);
}
Name OrderedNameDictionaryHandler::KeyAt(HeapObject table, int entry) {
if (table->IsSmallOrderedNameDictionary()) {
return Name::cast(SmallOrderedNameDictionary::cast(table)->KeyAt(entry));
}
return Name::cast(OrderedNameDictionary::cast(table)->KeyAt(entry));
}
int OrderedNameDictionaryHandler::NumberOfElements(HeapObject table) {
if (table->IsSmallOrderedNameDictionary()) {
return SmallOrderedNameDictionary::cast(table)->NumberOfElements();
}
return OrderedNameDictionary::cast(table)->NumberOfElements();
}
int OrderedNameDictionaryHandler::Capacity(HeapObject table) {
if (table->IsSmallOrderedNameDictionary()) {
return SmallOrderedNameDictionary::cast(table)->Capacity();
}
return OrderedNameDictionary::cast(table)->Capacity();
}
Handle<HeapObject> OrderedNameDictionaryHandler::Shrink(
Isolate* isolate, Handle<HeapObject> table) {
if (table->IsSmallOrderedNameDictionary()) {
Handle<SmallOrderedNameDictionary> small_dict =
Handle<SmallOrderedNameDictionary>::cast(table);
return SmallOrderedNameDictionary::Shrink(isolate, small_dict);
}
Handle<OrderedNameDictionary> large_dict =
Handle<OrderedNameDictionary>::cast(table);
return OrderedNameDictionary::Shrink(isolate, large_dict);
}
Handle<HeapObject> OrderedNameDictionaryHandler::DeleteEntry(
Isolate* isolate, Handle<HeapObject> table, int entry) {
DisallowHeapAllocation no_gc;
if (table->IsSmallOrderedNameDictionary()) {
Handle<SmallOrderedNameDictionary> small_dict =
Handle<SmallOrderedNameDictionary>::cast(table);
return SmallOrderedNameDictionary::DeleteEntry(isolate, small_dict, entry);
}
Handle<OrderedNameDictionary> large_dict =
Handle<OrderedNameDictionary>::cast(table);
return OrderedNameDictionary::DeleteEntry(isolate, large_dict, entry);
}
template <class Derived, class TableType>
void OrderedHashTableIterator<Derived, TableType>::Transition() {
DisallowHeapAllocation no_allocation;

View File

@ -223,6 +223,9 @@ class OrderedHashTable : public FixedArray {
}
OBJECT_CONSTRUCTORS(OrderedHashTable, FixedArray)
private:
friend class OrderedNameDictionaryHandler;
};
class OrderedHashSet : public OrderedHashTable<OrderedHashSet, 1> {
@ -354,6 +357,7 @@ class SmallOrderedHashTable : public HeapObject {
static MaybeHandle<Derived> Grow(Isolate* isolate, Handle<Derived> table);
int FindEntry(Isolate* isolate, Object key);
static Handle<Derived> Shrink(Isolate* isolate, Handle<Derived> table);
// Iterates only fields in the DataTable.
class BodyDescriptor;
@ -399,6 +403,12 @@ class SmallOrderedHashTable : public HeapObject {
int NumberOfBuckets() const { return getByte(NumberOfBucketsOffset(), 0); }
Object KeyAt(int entry) const {
DCHECK_LT(entry, Capacity());
Offset entry_offset = GetDataEntryOffset(entry, Derived::kKeyIndex);
return READ_FIELD(this, entry_offset);
}
DECL_VERIFIER(SmallOrderedHashTable)
static const int kMinCapacity = 4;
@ -484,12 +494,6 @@ class SmallOrderedHashTable : public HeapObject {
return READ_FIELD(this, entry_offset);
}
Object KeyAt(int entry) const {
DCHECK_LT(entry, Capacity());
Offset entry_offset = GetDataEntryOffset(entry, Derived::kKeyIndex);
return READ_FIELD(this, entry_offset);
}
int HashToBucket(int hash) const { return hash & (NumberOfBuckets() - 1); }
int HashToFirstEntry(int hash) const {
@ -575,6 +579,7 @@ class SmallOrderedHashSet : public SmallOrderedHashTable<SmallOrderedHashSet> {
DECL_CAST2(SmallOrderedHashSet)
DECL_PRINTER(SmallOrderedHashSet)
DECL_VERIFIER(SmallOrderedHashSet)
static const int kKeyIndex = 0;
static const int kEntrySize = 1;
@ -600,6 +605,7 @@ class SmallOrderedHashMap : public SmallOrderedHashTable<SmallOrderedHashMap> {
DECL_CAST2(SmallOrderedHashMap)
DECL_PRINTER(SmallOrderedHashMap)
DECL_VERIFIER(SmallOrderedHashMap)
static const int kKeyIndex = 0;
static const int kValueIndex = 1;
@ -672,6 +678,12 @@ class OrderedNameDictionary
Handle<Object> value,
PropertyDetails details);
void SetEntry(Isolate* isolate, int entry, Object key, Object value,
PropertyDetails details);
static Handle<OrderedNameDictionary> DeleteEntry(
Isolate* isolate, Handle<OrderedNameDictionary> table, int entry);
static Handle<OrderedNameDictionary> Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure = NOT_TENURED);
@ -711,8 +723,13 @@ class OrderedNameDictionaryHandler
static Handle<HeapObject> Add(Isolate* isolate, Handle<HeapObject> table,
Handle<Name> key, Handle<Object> value,
PropertyDetails details);
static Handle<HeapObject> Shrink(Isolate* isolate, Handle<HeapObject> table);
static int FindEntry(Isolate* isolate, HeapObject table, Object key);
static Handle<HeapObject> DeleteEntry(Isolate* isolate,
Handle<HeapObject> table, int entry);
static int FindEntry(Isolate* isolate, HeapObject table, Name key);
static void SetEntry(Isolate* isolate, HeapObject table, int entry,
Object key, Object value, PropertyDetails details);
// Returns the value for entry.
static Object ValueAt(HeapObject table, int entry);
@ -726,9 +743,14 @@ class OrderedNameDictionaryHandler
// Set the details for entry.
static void DetailsAtPut(HeapObject table, int entry, PropertyDetails value);
static Name KeyAt(HeapObject table, int entry);
static void SetHash(HeapObject table, int hash);
static int Hash(HeapObject table);
static int NumberOfElements(HeapObject table);
static int Capacity(HeapObject table);
static const int kNotFound = -1;
protected:
@ -742,6 +764,7 @@ class SmallOrderedNameDictionary
DECL_CAST2(SmallOrderedNameDictionary)
DECL_PRINTER(SmallOrderedNameDictionary)
DECL_VERIFIER(SmallOrderedNameDictionary)
// Returns the value for entry.
inline Object ValueAt(int entry);
@ -750,6 +773,9 @@ class SmallOrderedNameDictionary
Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
int new_capacity);
static Handle<SmallOrderedNameDictionary> DeleteEntry(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table, int entry);
// Set the value for entry.
inline void ValueAtPut(int entry, Object value);
@ -774,6 +800,10 @@ class SmallOrderedNameDictionary
static MaybeHandle<SmallOrderedNameDictionary> Add(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
Handle<Name> key, Handle<Object> value, PropertyDetails details);
void SetEntry(Isolate* isolate, int entry, Object key, Object value,
PropertyDetails details);
static inline RootIndex GetMapRootIndex();
OBJECT_CONSTRUCTORS(SmallOrderedNameDictionary,

View File

@ -1782,6 +1782,216 @@ TEST(OrderedNameDictionaryHandlerInsertion) {
CHECK(table->IsOrderedNameDictionary());
}
TEST(OrderedNameDictionarySetEntry) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<OrderedNameDictionary> dict = factory->NewOrderedNameDictionary();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(0, dict->NumberOfElements());
CHECK_EQ(0, dict->NumberOfDeletedElements());
Handle<String> key = factory->InternalizeUtf8String("foo");
Handle<String> value = factory->InternalizeUtf8String("bar");
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key));
PropertyDetails details = PropertyDetails::Empty();
dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
int entry = dict->FindEntry(isolate, *key);
CHECK_EQ(0, entry);
Handle<Object> found = handle(dict->ValueAt(entry), isolate);
CHECK_EQ(*found, *value);
// Change the value
Handle<String> other_value = isolate->factory()->InternalizeUtf8String("baz");
PropertyDetails other_details =
PropertyDetails(kAccessor, READ_ONLY, PropertyCellType::kNoCell);
dict->SetEntry(isolate, entry, *key, *other_value, other_details);
entry = dict->FindEntry(isolate, *key);
CHECK_EQ(0, entry);
found = handle(dict->ValueAt(entry), isolate);
CHECK_EQ(*found, *other_value);
found = handle(dict->KeyAt(entry), isolate);
CHECK_EQ(*found, *key);
PropertyDetails found_details = dict->DetailsAt(entry);
CHECK_EQ(found_details.AsSmi(), other_details.AsSmi());
}
TEST(SmallOrderedNameDictionarySetEntry) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<SmallOrderedNameDictionary> dict =
factory->NewSmallOrderedNameDictionary();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(0, dict->NumberOfElements());
Handle<String> key = factory->InternalizeUtf8String("foo");
Handle<String> value = factory->InternalizeUtf8String("bar");
CHECK_EQ(SmallOrderedNameDictionary::kNotFound,
dict->FindEntry(isolate, *key));
PropertyDetails details = PropertyDetails::Empty();
dict = SmallOrderedNameDictionary::Add(isolate, dict, key, value, details)
.ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
CHECK_EQ(0, dict->NumberOfDeletedElements());
int entry = dict->FindEntry(isolate, *key);
CHECK_EQ(0, entry);
Handle<Object> found = handle(dict->ValueAt(entry), isolate);
CHECK_EQ(*found, *value);
// Change the value
Handle<String> other_value = factory->InternalizeUtf8String("baz");
PropertyDetails other_details =
PropertyDetails(kAccessor, READ_ONLY, PropertyCellType::kNoCell);
dict->SetEntry(isolate, entry, *key, *other_value, other_details);
entry = dict->FindEntry(isolate, *key);
CHECK_EQ(0, entry);
found = handle(dict->ValueAt(entry), isolate);
CHECK_EQ(*found, *other_value);
found = handle(dict->KeyAt(entry), isolate);
CHECK_EQ(*found, *key);
PropertyDetails found_details = dict->DetailsAt(entry);
CHECK_EQ(found_details.AsSmi(), other_details.AsSmi());
}
TEST(OrderedNameDictionaryDeleteEntry) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<OrderedNameDictionary> dict = factory->NewOrderedNameDictionary();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(0, dict->NumberOfElements());
Handle<String> key = factory->InternalizeUtf8String("foo");
Handle<String> value = factory->InternalizeUtf8String("bar");
CHECK_EQ(OrderedNameDictionary::kNotFound, dict->FindEntry(isolate, *key));
PropertyDetails details = PropertyDetails::Empty();
dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
CHECK_EQ(0, dict->NumberOfDeletedElements());
int entry = dict->FindEntry(isolate, *key);
CHECK_EQ(0, entry);
dict = OrderedNameDictionary::DeleteEntry(isolate, dict, entry);
entry = dict->FindEntry(isolate, *key);
CHECK_EQ(OrderedNameDictionary::kNotFound, entry);
CHECK_EQ(0, dict->NumberOfElements());
char buf[10];
// Make sure we grow at least once.
CHECK_LT(OrderedNameDictionaryHandler::Capacity(*dict), 100);
for (int i = 0; i < 100; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
key = factory->InternalizeUtf8String(buf);
dict = OrderedNameDictionary::Add(isolate, dict, key, value, details);
DCHECK(key->IsUniqueName());
Verify(isolate, dict);
}
CHECK_EQ(100, dict->NumberOfElements());
// Initial dictionary has grown.
CHECK_EQ(0, dict->NumberOfDeletedElements());
for (int i = 0; i < 100; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
key = factory->InternalizeUtf8String(buf);
entry = dict->FindEntry(isolate, *key);
dict = OrderedNameDictionary::DeleteEntry(isolate, dict, entry);
Verify(isolate, dict);
entry = dict->FindEntry(isolate, *key);
CHECK_EQ(OrderedNameDictionary::kNotFound, entry);
}
CHECK_EQ(0, dict->NumberOfElements());
// Dictionary shrunk again.
CHECK_EQ(0, dict->NumberOfDeletedElements());
}
TEST(SmallOrderedNameDictionaryDeleteEntry) {
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
Factory* factory = isolate->factory();
HandleScope scope(isolate);
Handle<SmallOrderedNameDictionary> dict =
factory->NewSmallOrderedNameDictionary();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(0, dict->NumberOfElements());
Handle<String> key = factory->InternalizeUtf8String("foo");
Handle<String> value = factory->InternalizeUtf8String("bar");
CHECK_EQ(SmallOrderedNameDictionary::kNotFound,
dict->FindEntry(isolate, *key));
PropertyDetails details = PropertyDetails::Empty();
dict = SmallOrderedNameDictionary::Add(isolate, dict, key, value, details)
.ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
CHECK_EQ(0, dict->NumberOfDeletedElements());
int entry = dict->FindEntry(isolate, *key);
CHECK_EQ(0, entry);
dict = SmallOrderedNameDictionary::DeleteEntry(isolate, dict, entry);
entry = dict->FindEntry(isolate, *key);
CHECK_EQ(SmallOrderedNameDictionary::kNotFound, entry);
char buf[10];
// Make sure we grow at least once.
CHECK_LT(dict->Capacity(), SmallOrderedNameDictionary::kMaxCapacity);
for (int i = 0; i < SmallOrderedNameDictionary::kMaxCapacity; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
key = factory->InternalizeUtf8String(buf);
dict = SmallOrderedNameDictionary::Add(isolate, dict, key, value, details)
.ToHandleChecked();
DCHECK(key->IsUniqueName());
Verify(isolate, dict);
}
CHECK_EQ(SmallOrderedNameDictionary::kMaxCapacity, dict->NumberOfElements());
// Dictionary has grown.
CHECK_EQ(0, dict->NumberOfDeletedElements());
for (int i = 0; i < SmallOrderedNameDictionary::kMaxCapacity; i++) {
CHECK_LT(0, snprintf(buf, sizeof(buf), "foo%d", i));
key = factory->InternalizeUtf8String(buf);
entry = dict->FindEntry(isolate, *key);
dict = SmallOrderedNameDictionary::DeleteEntry(isolate, dict, entry);
Verify(isolate, dict);
entry = dict->FindEntry(isolate, *key);
CHECK_EQ(SmallOrderedNameDictionary::kNotFound, entry);
}
CHECK_EQ(0, dict->NumberOfElements());
// Dictionary shrunk.
CHECK_EQ(0, dict->NumberOfDeletedElements());
}
} // namespace test_orderedhashtable
} // namespace internal
} // namespace v8