Commit d0749b78 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran

[dict] Specialize SmallOrderedHashTable for Name dictionary

Bug: v8:6443, v8:7569
Change-Id: Iee039eddd07a7bbc38c8e9f7deca00d5183e702a
Reviewed-on: https://chromium-review.googlesource.com/c/1329697Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57438}
parent 0227b62f
......@@ -344,6 +344,7 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case STACK_FRAME_INFO_TYPE:
case SMALL_ORDERED_HASH_MAP_TYPE:
case SMALL_ORDERED_HASH_SET_TYPE:
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
case PROTOTYPE_INFO_TYPE:
case INTERPRETER_DATA_TYPE:
case TUPLE2_TYPE:
......
......@@ -517,34 +517,36 @@ Handle<FrameArray> Factory::NewFrameArray(int number_of_frames,
return Handle<FrameArray>::cast(result);
}
Handle<SmallOrderedHashSet> Factory::NewSmallOrderedHashSet(
int capacity, PretenureFlag pretenure) {
template <typename T>
Handle<T> Factory::AllocateSmallOrderedHashTable(Handle<Map> map, int capacity,
PretenureFlag pretenure) {
DCHECK_LE(0, capacity);
CHECK_LE(capacity, SmallOrderedHashSet::kMaxCapacity);
DCHECK_EQ(0, capacity % SmallOrderedHashSet::kLoadFactor);
CHECK_LE(capacity, T::kMaxCapacity);
DCHECK_EQ(0, capacity % T::kLoadFactor);
int size = SmallOrderedHashSet::SizeFor(capacity);
Map* map = *small_ordered_hash_set_map();
HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, map);
Handle<SmallOrderedHashSet> table(SmallOrderedHashSet::cast(result),
isolate());
int size = T::SizeFor(capacity);
HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, *map);
Handle<T> table(T::cast(result), isolate());
table->Initialize(isolate(), capacity);
return table;
}
Handle<SmallOrderedHashSet> Factory::NewSmallOrderedHashSet(
int capacity, PretenureFlag pretenure) {
return AllocateSmallOrderedHashTable<SmallOrderedHashSet>(
small_ordered_hash_set_map(), capacity, pretenure);
}
Handle<SmallOrderedHashMap> Factory::NewSmallOrderedHashMap(
int capacity, PretenureFlag pretenure) {
DCHECK_LE(0, capacity);
CHECK_LE(capacity, SmallOrderedHashMap::kMaxCapacity);
DCHECK_EQ(0, capacity % SmallOrderedHashMap::kLoadFactor);
return AllocateSmallOrderedHashTable<SmallOrderedHashMap>(
small_ordered_hash_map_map(), capacity, pretenure);
}
int size = SmallOrderedHashMap::SizeFor(capacity);
Map* map = *small_ordered_hash_map_map();
HeapObject* result = AllocateRawWithImmortalMap(size, pretenure, map);
Handle<SmallOrderedHashMap> table(SmallOrderedHashMap::cast(result),
isolate());
table->Initialize(isolate(), capacity);
return table;
Handle<SmallOrderedNameDictionary> Factory::NewSmallOrderedNameDictionary(
int capacity, PretenureFlag pretenure) {
return AllocateSmallOrderedHashTable<SmallOrderedNameDictionary>(
small_ordered_name_dictionary_map(), capacity, pretenure);
}
Handle<OrderedHashSet> Factory::NewOrderedHashSet() {
......
......@@ -185,6 +185,9 @@ class V8_EXPORT_PRIVATE Factory {
Handle<SmallOrderedHashMap> NewSmallOrderedHashMap(
int capacity = SmallOrderedHashMap::kMinCapacity,
PretenureFlag pretenure = NOT_TENURED);
Handle<SmallOrderedNameDictionary> NewSmallOrderedNameDictionary(
int capacity = SmallOrderedHashMap::kMinCapacity,
PretenureFlag pretenure = NOT_TENURED);
// Create a new PrototypeInfo struct.
Handle<PrototypeInfo> NewPrototypeInfo();
......@@ -942,6 +945,10 @@ class V8_EXPORT_PRIVATE Factory {
int length, Object* filler,
PretenureFlag pretenure);
template <typename T>
Handle<T> AllocateSmallOrderedHashTable(Handle<Map> map, int capacity,
PretenureFlag pretenure);
// Creates a heap object based on the map. The fields of the heap object are
// not initialized, it's the responsibility of the caller to do that.
HeapObject* New(Handle<Map> map, PretenureFlag pretenure);
......
......@@ -64,6 +64,7 @@ class WasmInstanceObject;
V(SlicedString, SlicedString*) \
V(SmallOrderedHashMap, SmallOrderedHashMap*) \
V(SmallOrderedHashSet, SmallOrderedHashSet*) \
V(SmallOrderedNameDictionary, SmallOrderedNameDictionary*) \
V(Symbol, Symbol*) \
V(ThinString, ThinString*) \
V(TransitionArray, TransitionArray*) \
......
......@@ -413,6 +413,8 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_VARSIZE_MAP(PROPERTY_ARRAY_TYPE, property_array)
ALLOCATE_VARSIZE_MAP(SMALL_ORDERED_HASH_MAP_TYPE, small_ordered_hash_map)
ALLOCATE_VARSIZE_MAP(SMALL_ORDERED_HASH_SET_TYPE, small_ordered_hash_set)
ALLOCATE_VARSIZE_MAP(SMALL_ORDERED_NAME_DICTIONARY_TYPE,
small_ordered_name_dictionary)
#define ALLOCATE_FIXED_TYPED_ARRAY_MAP(Type, type, TYPE, ctype) \
ALLOCATE_VARSIZE_MAP(FIXED_##TYPE##_ARRAY_TYPE, fixed_##type##_array)
......
......@@ -889,6 +889,10 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
return Op::template apply<
SmallOrderedHashTable<SmallOrderedHashMap>::BodyDescriptor>(p1, p2,
p3, p4);
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
return Op::template apply<
SmallOrderedHashTable<SmallOrderedNameDictionary>::BodyDescriptor>(
p1, p2, p3, p4);
case CODE_DATA_CONTAINER_TYPE:
return Op::template apply<CodeDataContainer::BodyDescriptor>(p1, p2, p3,
p4);
......
......@@ -379,6 +379,10 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
case SMALL_ORDERED_HASH_MAP_TYPE:
SmallOrderedHashMap::cast(this)->SmallOrderedHashTableVerify(isolate);
break;
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
SmallOrderedNameDictionary::cast(this)->SmallOrderedHashTableVerify(
isolate);
break;
case CODE_DATA_CONTAINER_TYPE:
CodeDataContainer::cast(this)->CodeDataContainerVerify(isolate);
break;
......@@ -1484,6 +1488,8 @@ template void SmallOrderedHashTable<
SmallOrderedHashMap>::SmallOrderedHashTableVerify(Isolate* isolate);
template void SmallOrderedHashTable<
SmallOrderedHashSet>::SmallOrderedHashTableVerify(Isolate* isolate);
template void SmallOrderedHashTable<
SmallOrderedNameDictionary>::SmallOrderedHashTableVerify(Isolate* isolate);
void JSRegExp::JSRegExpVerify(Isolate* isolate) {
JSObjectVerify(isolate);
......
......@@ -168,6 +168,7 @@ namespace internal {
V(SHARED_FUNCTION_INFO_TYPE) \
V(SMALL_ORDERED_HASH_MAP_TYPE) \
V(SMALL_ORDERED_HASH_SET_TYPE) \
V(SMALL_ORDERED_NAME_DICTIONARY_TYPE) \
V(STORE_HANDLER_TYPE) \
V(UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE) \
V(UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE) \
......
......@@ -401,7 +401,8 @@ bool HeapObject::IsMapCache() const { return IsHashTable(); }
bool HeapObject::IsObjectHashTable() const { return IsHashTable(); }
bool Object::IsSmallOrderedHashTable() const {
return IsSmallOrderedHashSet() || IsSmallOrderedHashMap();
return IsSmallOrderedHashSet() || IsSmallOrderedHashMap() ||
IsSmallOrderedNameDictionary();
}
bool Object::IsPrimitive() const {
......@@ -499,6 +500,7 @@ CAST_ACCESSOR(ScopeInfo)
CAST_ACCESSOR(SimpleNumberDictionary)
CAST_ACCESSOR(SmallOrderedHashMap)
CAST_ACCESSOR(SmallOrderedHashSet)
CAST_ACCESSOR(SmallOrderedNameDictionary)
CAST_ACCESSOR(StringSet)
CAST_ACCESSOR(StringTable)
CAST_ACCESSOR(Struct)
......@@ -1080,6 +1082,7 @@ bool HeapObject::NeedsRehashing() const {
case HASH_TABLE_TYPE:
case SMALL_ORDERED_HASH_MAP_TYPE:
case SMALL_ORDERED_HASH_SET_TYPE:
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
return true;
default:
return false;
......@@ -1549,14 +1552,18 @@ int HeapObject::SizeFromMap(Map* map) const {
return SmallOrderedHashSet::SizeFor(
reinterpret_cast<const SmallOrderedHashSet*>(this)->Capacity());
}
if (instance_type == PROPERTY_ARRAY_TYPE) {
return PropertyArray::SizeFor(
PropertyArray::cast(this)->synchronized_length());
}
if (instance_type == SMALL_ORDERED_HASH_MAP_TYPE) {
return SmallOrderedHashMap::SizeFor(
reinterpret_cast<const SmallOrderedHashMap*>(this)->Capacity());
}
if (instance_type == SMALL_ORDERED_NAME_DICTIONARY_TYPE) {
return SmallOrderedNameDictionary::SizeFor(
reinterpret_cast<const SmallOrderedNameDictionary*>(this)->Capacity());
}
if (instance_type == PROPERTY_ARRAY_TYPE) {
return PropertyArray::SizeFor(
PropertyArray::cast(this)->synchronized_length());
}
if (instance_type == FEEDBACK_VECTOR_TYPE) {
return FeedbackVector::SizeFor(
reinterpret_cast<const FeedbackVector*>(this)->length());
......
......@@ -430,6 +430,7 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case UNCACHED_EXTERNAL_STRING_WITH_ONE_BYTE_DATA_TYPE:
case SMALL_ORDERED_HASH_MAP_TYPE:
case SMALL_ORDERED_HASH_SET_TYPE:
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE:
case JS_STRING_ITERATOR_TYPE:
// TODO(all): Handle these types too.
......
......@@ -3197,6 +3197,9 @@ VisitorId Map::GetVisitorId(Map* map) {
case SMALL_ORDERED_HASH_SET_TYPE:
return kVisitSmallOrderedHashSet;
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
return kVisitSmallOrderedNameDictionary;
case CODE_DATA_CONTAINER_TYPE:
return kVisitCodeDataContainer;
......@@ -3848,6 +3851,8 @@ bool HeapObject::CanBeRehashed() const {
return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
case SMALL_ORDERED_HASH_SET_TYPE:
return SmallOrderedHashMap::cast(this)->NumberOfElements() == 0;
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
return SmallOrderedNameDictionary::cast(this)->NumberOfElements() == 0;
default:
return false;
}
......@@ -3887,6 +3892,9 @@ void HeapObject::RehashBasedOnMap(Isolate* isolate) {
case SMALL_ORDERED_HASH_SET_TYPE:
DCHECK_EQ(0, SmallOrderedHashSet::cast(this)->NumberOfElements());
break;
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
DCHECK_EQ(0, SmallOrderedNameDictionary::cast(this)->NumberOfElements());
break;
default:
break;
}
......
......@@ -464,6 +464,7 @@ enum InstanceType : uint16_t {
SHARED_FUNCTION_INFO_TYPE,
SMALL_ORDERED_HASH_MAP_TYPE,
SMALL_ORDERED_HASH_SET_TYPE,
SMALL_ORDERED_NAME_DICTIONARY_TYPE,
STORE_HANDLER_TYPE,
UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE,
UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE,
......@@ -835,6 +836,7 @@ class ZoneForwardList;
V(SloppyArgumentsElements) \
V(SmallOrderedHashMap) \
V(SmallOrderedHashSet) \
V(SmallOrderedNameDictionary) \
V(SourcePositionTableWithFrameCache) \
V(StoreHandler) \
V(String) \
......@@ -977,6 +979,7 @@ class ZoneForwardList;
V(SimpleNumberDictionary, SIMPLE_NUMBER_DICTIONARY_TYPE) \
V(SmallOrderedHashMap, SMALL_ORDERED_HASH_MAP_TYPE) \
V(SmallOrderedHashSet, SMALL_ORDERED_HASH_SET_TYPE) \
V(SmallOrderedNameDictionary, SMALL_ORDERED_NAME_DICTIONARY_TYPE) \
V(SourcePositionTableWithFrameCache, TUPLE2_TYPE) \
V(StoreHandler, STORE_HANDLER_TYPE) \
V(StringTable, STRING_TABLE_TYPE) \
......
......@@ -57,6 +57,7 @@ namespace internal {
V(SlicedString) \
V(SmallOrderedHashMap) \
V(SmallOrderedHashSet) \
V(SmallOrderedNameDictionary) \
V(Struct) \
V(Symbol) \
V(ThinString) \
......
......@@ -25,6 +25,10 @@ RootIndex OrderedNameDictionary::GetMapRootIndex() {
return RootIndex::kOrderedNameDictionaryMap;
}
RootIndex SmallOrderedNameDictionary::GetMapRootIndex() {
return RootIndex::kSmallOrderedNameDictionaryMap;
}
RootIndex SmallOrderedHashMap::GetMapRootIndex() {
return RootIndex::kSmallOrderedHashMapMap;
}
......
......@@ -438,6 +438,13 @@ SmallOrderedHashTable<SmallOrderedHashMap>::Allocate(Isolate* isolate,
return isolate->factory()->NewSmallOrderedHashMap(capacity, pretenure);
}
template <>
Handle<SmallOrderedNameDictionary>
SmallOrderedHashTable<SmallOrderedNameDictionary>::Allocate(
Isolate* isolate, int capacity, PretenureFlag pretenure) {
return isolate->factory()->NewSmallOrderedNameDictionary(capacity, pretenure);
}
template <class Derived>
void SmallOrderedHashTable<Derived>::Initialize(Isolate* isolate,
int capacity) {
......@@ -548,6 +555,47 @@ MaybeHandle<SmallOrderedHashMap> SmallOrderedHashMap::Add(
return table;
}
MaybeHandle<SmallOrderedNameDictionary> SmallOrderedNameDictionary::Add(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
Handle<Name> key, Handle<Object> value, PropertyDetails details) {
DCHECK(!table->HasKey(isolate, key));
if (table->UsedCapacity() >= table->Capacity()) {
MaybeHandle<SmallOrderedNameDictionary> new_table =
SmallOrderedNameDictionary::Grow(isolate, table);
if (!new_table.ToHandle(&table)) {
return MaybeHandle<SmallOrderedNameDictionary>();
}
}
int hash = key->GetOrCreateHash(isolate)->value();
int nof = table->NumberOfElements();
// Read the existing bucket values.
int bucket = table->HashToBucket(hash);
int previous_entry = table->HashToFirstEntry(hash);
// Insert a new entry at the end,
int new_entry = nof + table->NumberOfDeletedElements();
table->SetDataEntry(new_entry, SmallOrderedNameDictionary::kValueIndex,
*value);
table->SetDataEntry(new_entry, SmallOrderedNameDictionary::kKeyIndex, *key);
// TODO(gsathya): PropertyDetails should be stored as part of the
// data table to save more memory.
table->SetDataEntry(new_entry,
SmallOrderedNameDictionary::kPropertyDetailsIndex,
details.AsSmi());
table->SetFirstEntry(bucket, new_entry);
table->SetNextEntry(new_entry, previous_entry);
// and update book keeping.
table->SetNumberOfElements(nof + 1);
return table;
}
template <class Derived>
bool SmallOrderedHashTable<Derived>::HasKey(Isolate* isolate,
Handle<Object> key) {
......@@ -668,6 +716,11 @@ template bool SmallOrderedHashTable<SmallOrderedHashMap>::Delete(
template bool SmallOrderedHashTable<SmallOrderedHashSet>::Delete(
Isolate* isolate, SmallOrderedHashSet* table, Object* key);
template void SmallOrderedHashTable<SmallOrderedNameDictionary>::Initialize(
Isolate* isolate, int capacity);
template bool SmallOrderedHashTable<SmallOrderedNameDictionary>::HasKey(
Isolate* isolate, Handle<Object> key);
template <class SmallTable, class LargeTable>
Handle<HeapObject> OrderedHashTableHandler<SmallTable, LargeTable>::Allocate(
Isolate* isolate, int capacity) {
......
......@@ -620,6 +620,27 @@ class OrderedNameDictionary
static const int kPropertyDetailsOffset = 2;
};
class SmallOrderedNameDictionary
: public SmallOrderedHashTable<SmallOrderedNameDictionary> {
public:
DECL_CAST(SmallOrderedNameDictionary)
DECL_PRINTER(SmallOrderedNameDictionary)
static const int kKeyIndex = 0;
static const int kValueIndex = 1;
static const int kPropertyDetailsIndex = 2;
static const int kEntrySize = 3;
// Adds |value| to |table|, if the capacity isn't enough, a new
// table is created. The original |table| is returned if there is
// capacity to store |value| otherwise the new table is returned.
static MaybeHandle<SmallOrderedNameDictionary> Add(
Isolate* isolate, Handle<SmallOrderedNameDictionary> table,
Handle<Name> key, Handle<Object> value, PropertyDetails details);
static inline RootIndex GetMapRootIndex();
};
class JSCollectionIterator : public JSObject {
public:
// [table]: the backing hash table mapping keys to values.
......
......@@ -111,6 +111,7 @@ class RootVisitor;
V(Map*, sloppy_arguments_elements_map, SloppyArgumentsElementsMap) \
V(Map*, small_ordered_hash_map_map, SmallOrderedHashMapMap) \
V(Map*, small_ordered_hash_set_map, SmallOrderedHashSetMap) \
V(Map*, small_ordered_name_dictionary_map, SmallOrderedNameDictionaryMap) \
V(Map*, string_table_map, StringTableMap) \
V(Map*, uncompiled_data_without_pre_parsed_scope_map, \
UncompiledDataWithoutPreParsedScopeMap) \
......
......@@ -1468,6 +1468,40 @@ TEST(OrderedNameDictionaryDetailsAtAndDetailsAtPut) {
CHECK_EQ(other.AsSmi(), found.AsSmi());
}
TEST(SmallOrderedNameDictionaryInsertion) {
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> key1 = isolate->factory()->InternalizeUtf8String("foo");
Handle<String> value = isolate->factory()->InternalizeUtf8String("foo");
CHECK(!dict->HasKey(isolate, key1));
PropertyDetails details = PropertyDetails::Empty();
dict = SmallOrderedNameDictionary::Add(isolate, dict, key1, value, details)
.ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(1, dict->NumberOfElements());
CHECK(dict->HasKey(isolate, key1));
Handle<Symbol> key2 = factory->NewSymbol();
CHECK(!dict->HasKey(isolate, key2));
dict = SmallOrderedNameDictionary::Add(isolate, dict, key2, value, details)
.ToHandleChecked();
Verify(isolate, dict);
CHECK_EQ(2, dict->NumberOfBuckets());
CHECK_EQ(2, dict->NumberOfElements());
CHECK(dict->HasKey(isolate, key1));
CHECK(dict->HasKey(isolate, key2));
}
} // namespace test_orderedhashtable
} // namespace internal
} // namespace v8
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment