[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:
parent
5d40e9de86
commit
0bd4e348e0
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user