[ic] Use UnseededNumberDictionary as a storage for names in TypeFeedbackMetadata.
The serializer does not support serialization of HashTables in general because after deserialization it might be necessary to rehash the table. However the UnseededNumberDictionary does not require rehashing and this CL allows them to be serialized. This CL also changes the shape of UnseededNumberDictionary: the details field is no longer part of the entry since no one needs it. BUG=chromium:576312, chromium:623516 Review-Url: https://codereview.chromium.org/2102073002 Cr-Commit-Position: refs/heads/master@{#37336}
This commit is contained in:
parent
61c137c811
commit
7031861990
@ -2342,6 +2342,7 @@ bool Heap::CreateInitialMaps() {
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, hash_table)
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, ordered_hash_table)
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, unseeded_number_dictionary)
|
||||
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, function_context)
|
||||
ALLOCATE_VARSIZE_MAP(FIXED_ARRAY_TYPE, catch_context)
|
||||
|
@ -46,6 +46,7 @@ using v8::MemoryPressureLevel;
|
||||
V(Map, fixed_array_map, FixedArrayMap) \
|
||||
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \
|
||||
V(Map, hash_table_map, HashTableMap) \
|
||||
V(Map, unseeded_number_dictionary_map, UnseededNumberDictionaryMap) \
|
||||
V(Map, symbol_map, SymbolMap) \
|
||||
V(Map, one_byte_string_map, OneByteStringMap) \
|
||||
V(Map, one_byte_internalized_string_map, OneByteInternalizedStringMap) \
|
||||
|
@ -850,9 +850,8 @@ bool Object::IsSeededNumberDictionary() const {
|
||||
return IsDictionary();
|
||||
}
|
||||
|
||||
|
||||
bool Object::IsUnseededNumberDictionary() const {
|
||||
return IsDictionary();
|
||||
bool HeapObject::IsUnseededNumberDictionary() const {
|
||||
return map() == GetHeap()->unseeded_number_dictionary_map();
|
||||
}
|
||||
|
||||
bool HeapObject::IsStringTable() const { return IsHashTable(); }
|
||||
@ -3063,6 +3062,10 @@ void HashTableBase::SetNumberOfDeletedElements(int nod) {
|
||||
set(kNumberOfDeletedElementsIndex, Smi::FromInt(nod));
|
||||
}
|
||||
|
||||
template <typename Key>
|
||||
Map* BaseShape<Key>::GetMap(Isolate* isolate) {
|
||||
return isolate->heap()->hash_table_map();
|
||||
}
|
||||
|
||||
template <typename Derived, typename Shape, typename Key>
|
||||
int HashTable<Derived, Shape, Key>::FindEntry(Key key) {
|
||||
@ -7473,14 +7476,16 @@ void BaseDictionaryShape<Key>::SetEntry(Dictionary* dict, int entry,
|
||||
Handle<Object> key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details) {
|
||||
STATIC_ASSERT(Dictionary::kEntrySize == 3);
|
||||
STATIC_ASSERT(Dictionary::kEntrySize == 2 || Dictionary::kEntrySize == 3);
|
||||
DCHECK(!key->IsName() || details.dictionary_index() > 0);
|
||||
int index = dict->EntryToIndex(entry);
|
||||
DisallowHeapAllocation no_gc;
|
||||
WriteBarrierMode mode = dict->GetWriteBarrierMode(no_gc);
|
||||
dict->set(index + Dictionary::kEntryKeyIndex, *key, mode);
|
||||
dict->set(index + Dictionary::kEntryValueIndex, *value, mode);
|
||||
dict->set(index + Dictionary::kEntryDetailsIndex, details.AsSmi());
|
||||
if (Dictionary::kEntrySize == 3) {
|
||||
dict->set(index + Dictionary::kEntryDetailsIndex, details.AsSmi());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -7517,6 +7522,9 @@ uint32_t UnseededNumberDictionaryShape::HashForObject(uint32_t key,
|
||||
return ComputeIntegerHash(static_cast<uint32_t>(other->Number()), 0);
|
||||
}
|
||||
|
||||
Map* UnseededNumberDictionaryShape::GetMap(Isolate* isolate) {
|
||||
return *isolate->factory()->unseeded_number_dictionary_map();
|
||||
}
|
||||
|
||||
uint32_t SeededNumberDictionaryShape::SeededHash(uint32_t key, uint32_t seed) {
|
||||
return ComputeIntegerHash(key, seed);
|
||||
|
@ -16189,7 +16189,7 @@ Handle<Derived> HashTable<Derived, Shape, Key>::New(
|
||||
Factory* factory = isolate->factory();
|
||||
int length = EntryToIndex(capacity);
|
||||
Handle<FixedArray> array = factory->NewFixedArray(length, pretenure);
|
||||
array->set_map_no_write_barrier(*factory->hash_table_map());
|
||||
array->set_map_no_write_barrier(Shape::GetMap(isolate));
|
||||
Handle<Derived> table = Handle<Derived>::cast(array);
|
||||
|
||||
table->SetNumberOfElements(0);
|
||||
|
@ -980,6 +980,7 @@ template <class C> inline bool Is(Object* obj);
|
||||
V(JSRegExp) \
|
||||
V(HashTable) \
|
||||
V(Dictionary) \
|
||||
V(UnseededNumberDictionary) \
|
||||
V(StringTable) \
|
||||
V(StringSet) \
|
||||
V(NormalizedMapCache) \
|
||||
@ -1078,7 +1079,6 @@ class Object {
|
||||
INLINE(bool IsNameDictionary() const);
|
||||
INLINE(bool IsGlobalDictionary() const);
|
||||
INLINE(bool IsSeededNumberDictionary() const);
|
||||
INLINE(bool IsUnseededNumberDictionary() const);
|
||||
INLINE(bool IsOrderedHashSet() const);
|
||||
INLINE(bool IsOrderedHashMap() const);
|
||||
|
||||
@ -3124,6 +3124,7 @@ class BaseShape {
|
||||
DCHECK(UsesSeed);
|
||||
return HashForObject(key, object);
|
||||
}
|
||||
static inline Map* GetMap(Isolate* isolate);
|
||||
};
|
||||
|
||||
|
||||
@ -3646,7 +3647,6 @@ class NumberDictionaryShape : public BaseDictionaryShape<uint32_t> {
|
||||
public:
|
||||
static inline bool IsMatch(uint32_t key, Object* other);
|
||||
static inline Handle<Object> AsHandle(Isolate* isolate, uint32_t key);
|
||||
static const int kEntrySize = 3;
|
||||
static const bool kIsEnumerable = false;
|
||||
};
|
||||
|
||||
@ -3655,6 +3655,7 @@ class SeededNumberDictionaryShape : public NumberDictionaryShape {
|
||||
public:
|
||||
static const bool UsesSeed = true;
|
||||
static const int kPrefixSize = 2;
|
||||
static const int kEntrySize = 3;
|
||||
|
||||
static inline uint32_t SeededHash(uint32_t key, uint32_t seed);
|
||||
static inline uint32_t SeededHashForObject(uint32_t key,
|
||||
@ -3666,9 +3667,24 @@ class SeededNumberDictionaryShape : public NumberDictionaryShape {
|
||||
class UnseededNumberDictionaryShape : public NumberDictionaryShape {
|
||||
public:
|
||||
static const int kPrefixSize = 0;
|
||||
static const int kEntrySize = 2;
|
||||
|
||||
static inline uint32_t Hash(uint32_t key);
|
||||
static inline uint32_t HashForObject(uint32_t key, Object* object);
|
||||
|
||||
template <typename Dictionary>
|
||||
static inline PropertyDetails DetailsAt(Dictionary* dict, int entry) {
|
||||
UNREACHABLE();
|
||||
return PropertyDetails::Empty();
|
||||
}
|
||||
|
||||
template <typename Dictionary>
|
||||
static inline void DetailsAtPut(Dictionary* dict, int entry,
|
||||
PropertyDetails value) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static inline Map* GetMap(Isolate* isolate);
|
||||
};
|
||||
|
||||
|
||||
|
@ -39,20 +39,13 @@ FeedbackVectorSlotKind TypeFeedbackMetadata::GetKind(
|
||||
|
||||
String* TypeFeedbackMetadata::GetName(FeedbackVectorSlot slot) const {
|
||||
DCHECK(SlotRequiresName(GetKind(slot)));
|
||||
FixedArray* names = FixedArray::cast(get(kNamesTableIndex));
|
||||
// TODO(ishell): consider using binary search here or even Dictionary when we
|
||||
// have more ICs with names.
|
||||
Smi* key = Smi::FromInt(slot.ToInt());
|
||||
for (int entry = 0; entry < names->length(); entry += kNameTableEntrySize) {
|
||||
Object* current_key = names->get(entry + kNameTableSlotIndex);
|
||||
if (current_key == key) {
|
||||
Object* name = names->get(entry + kNameTableNameIndex);
|
||||
DCHECK(name->IsString());
|
||||
return String::cast(name);
|
||||
}
|
||||
}
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
UnseededNumberDictionary* names =
|
||||
UnseededNumberDictionary::cast(get(kNamesTableIndex));
|
||||
int entry = names->FindEntry(GetIsolate(), slot.ToInt());
|
||||
CHECK_NE(UnseededNumberDictionary::kNotFound, entry);
|
||||
Object* name = names->ValueAt(entry);
|
||||
DCHECK(name->IsString());
|
||||
return String::cast(name);
|
||||
}
|
||||
|
||||
void TypeFeedbackMetadata::SetKind(FeedbackVectorSlot slot,
|
||||
@ -107,10 +100,9 @@ Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(Isolate* isolate,
|
||||
// Add names to NamesTable.
|
||||
const int name_count = spec->name_count();
|
||||
|
||||
Handle<FixedArray> names =
|
||||
name_count == 0
|
||||
? factory->empty_fixed_array()
|
||||
: factory->NewFixedArray(name_count * kNameTableEntrySize);
|
||||
Handle<UnseededNumberDictionary> names =
|
||||
UnseededNumberDictionary::New(isolate, name_count);
|
||||
|
||||
int name_index = 0;
|
||||
for (int i = 0; i < slot_count; i++) {
|
||||
FeedbackVectorSlotKind kind = spec->GetKind(i);
|
||||
@ -118,9 +110,7 @@ Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New(Isolate* isolate,
|
||||
if (SlotRequiresName(kind)) {
|
||||
Handle<String> name = spec->GetName(name_index);
|
||||
DCHECK(!name.is_null());
|
||||
int entry = name_index * kNameTableEntrySize;
|
||||
names->set(entry + kNameTableSlotIndex, Smi::FromInt(i));
|
||||
names->set(entry + kNameTableNameIndex, *name);
|
||||
names = UnseededNumberDictionary::AtNumberPut(names, i, name);
|
||||
name_index++;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ TypeFeedbackOracle::TypeFeedbackOracle(
|
||||
Handle<TypeFeedbackVector> feedback_vector, Handle<Context> native_context)
|
||||
: native_context_(native_context), isolate_(isolate), zone_(zone) {
|
||||
BuildDictionary(code);
|
||||
DCHECK(dictionary_->IsDictionary());
|
||||
DCHECK(dictionary_->IsUnseededNumberDictionary());
|
||||
// We make a copy of the feedback vector because a GC could clear
|
||||
// the type feedback info contained therein.
|
||||
// TODO(mvstanton): revisit the decision to copy when we weakly
|
||||
|
Loading…
Reference in New Issue
Block a user