[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:
ishell 2016-06-28 09:15:18 -07:00 committed by Commit bot
parent 61c137c811
commit 7031861990
7 changed files with 46 additions and 30 deletions

View File

@ -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)

View File

@ -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) \

View File

@ -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);

View File

@ -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);

View File

@ -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);
};

View File

@ -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++;
}
}

View File

@ -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