[dictionary] Move Name into PropertyCell to save space in overallocated hashtable
Bug: Change-Id: I56bfd921d63783ddaa74133dde5f3daf776e68ca Reviewed-on: https://chromium-review.googlesource.com/548115 Commit-Queue: Toon Verwaest <verwaest@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Cr-Commit-Position: refs/heads/master@{#46250}
This commit is contained in:
parent
189c8263e5
commit
e91c6dc7a9
@ -5012,22 +5012,16 @@ void Genesis::TransferNamedProperties(Handle<JSObject> from,
|
||||
// Copy all keys and values in enumeration order.
|
||||
Handle<GlobalDictionary> properties =
|
||||
Handle<GlobalDictionary>(from->global_dictionary());
|
||||
Handle<FixedArray> key_indices =
|
||||
GlobalDictionary::IterationIndices(properties);
|
||||
for (int i = 0; i < key_indices->length(); i++) {
|
||||
int key_index = Smi::cast(key_indices->get(i))->value();
|
||||
Object* raw_key = properties->KeyAt(key_index);
|
||||
DCHECK(properties->IsKey(isolate(), raw_key));
|
||||
DCHECK(raw_key->IsName());
|
||||
Handle<FixedArray> indices = GlobalDictionary::IterationIndices(properties);
|
||||
for (int i = 0; i < indices->length(); i++) {
|
||||
int index = Smi::cast(indices->get(i))->value();
|
||||
// If the property is already there we skip it.
|
||||
Handle<Name> key(Name::cast(raw_key), isolate());
|
||||
Handle<PropertyCell> cell(properties->CellAt(index));
|
||||
Handle<Name> key(cell->name(), isolate());
|
||||
LookupIterator it(to, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
|
||||
CHECK_NE(LookupIterator::ACCESS_CHECK, it.state());
|
||||
if (it.IsFound()) continue;
|
||||
// Set the property.
|
||||
DCHECK(properties->ValueAt(key_index)->IsPropertyCell());
|
||||
Handle<PropertyCell> cell(
|
||||
PropertyCell::cast(properties->ValueAt(key_index)), isolate());
|
||||
Handle<Object> value(cell->value(), isolate());
|
||||
if (value->IsTheHole(isolate())) continue;
|
||||
PropertyDetails details = cell->property_details();
|
||||
|
@ -4968,6 +4968,19 @@ void CodeStubAssembler::SetNextEnumerationIndex(Node* dictionary,
|
||||
next_enum_index_smi, SKIP_WRITE_BARRIER);
|
||||
}
|
||||
|
||||
template <>
|
||||
Node* CodeStubAssembler::LoadName<NameDictionary>(Node* key) {
|
||||
CSA_ASSERT(this, Word32Or(IsTheHole(key), IsName(key)));
|
||||
return key;
|
||||
}
|
||||
|
||||
template <>
|
||||
Node* CodeStubAssembler::LoadName<GlobalDictionary>(Node* key) {
|
||||
CSA_ASSERT(this, IsPropertyCell(key));
|
||||
CSA_ASSERT(this, IsNotTheHole(key));
|
||||
return LoadObjectField(key, PropertyCell::kNameOffset);
|
||||
}
|
||||
|
||||
template <typename Dictionary>
|
||||
void CodeStubAssembler::NameDictionaryLookup(Node* dictionary,
|
||||
Node* unique_name, Label* if_found,
|
||||
@ -4988,12 +5001,15 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary,
|
||||
// See Dictionary::FirstProbe().
|
||||
Node* count = IntPtrConstant(0);
|
||||
Node* entry = WordAnd(hash, mask);
|
||||
Node* undefined = UndefinedConstant();
|
||||
|
||||
for (int i = 0; i < inlined_probes; i++) {
|
||||
Node* index = EntryToIndex<Dictionary>(entry);
|
||||
var_name_index->Bind(index);
|
||||
|
||||
Node* current = LoadFixedArrayElement(dictionary, index);
|
||||
GotoIf(WordEqual(current, undefined), if_not_found);
|
||||
current = LoadName<Dictionary>(current);
|
||||
GotoIf(WordEqual(current, unique_name), if_found);
|
||||
|
||||
// See Dictionary::NextProbe().
|
||||
@ -5005,7 +5021,6 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary,
|
||||
var_name_index->Bind(IntPtrConstant(0));
|
||||
}
|
||||
|
||||
Node* undefined = UndefinedConstant();
|
||||
Node* the_hole = mode == kFindExisting ? nullptr : TheHoleConstant();
|
||||
|
||||
VARIABLE(var_count, MachineType::PointerRepresentation(), count);
|
||||
@ -5023,6 +5038,7 @@ void CodeStubAssembler::NameDictionaryLookup(Node* dictionary,
|
||||
Node* current = LoadFixedArrayElement(dictionary, index);
|
||||
GotoIf(WordEqual(current, undefined), if_not_found);
|
||||
if (mode == kFindExisting) {
|
||||
current = LoadName<Dictionary>(current);
|
||||
GotoIf(WordEqual(current, unique_name), if_found);
|
||||
} else {
|
||||
DCHECK_EQ(kFindInsertionIndex, mode);
|
||||
@ -5589,8 +5605,8 @@ void CodeStubAssembler::LoadPropertyFromGlobalDictionary(Node* dictionary,
|
||||
Comment("[ LoadPropertyFromGlobalDictionary");
|
||||
CSA_ASSERT(this, IsDictionary(dictionary));
|
||||
|
||||
Node* property_cell =
|
||||
LoadValueByKeyIndex<GlobalDictionary>(dictionary, name_index);
|
||||
Node* property_cell = LoadFixedArrayElement(dictionary, name_index);
|
||||
CSA_ASSERT(this, IsPropertyCell(property_cell));
|
||||
|
||||
Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
|
||||
GotoIf(WordEqual(value, TheHoleConstant()), if_deleted);
|
||||
|
@ -1137,6 +1137,10 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
// {if_not_found}.
|
||||
static const int kInlinedDictionaryProbes = 4;
|
||||
enum LookupMode { kFindExisting, kFindInsertionIndex };
|
||||
|
||||
template <typename Dictionary>
|
||||
Node* LoadName(Node* key);
|
||||
|
||||
template <typename Dictionary>
|
||||
void NameDictionaryLookup(Node* dictionary, Node* unique_name,
|
||||
Label* if_found, Variable* var_name_index,
|
||||
|
@ -1435,7 +1435,6 @@ class DictionaryElementsAccessor
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* key = dict->KeyAt(i);
|
||||
if (!dict->IsKey(isolate, key)) continue;
|
||||
DCHECK(!dict->IsDeleted(i));
|
||||
PropertyDetails details = dict->DetailsAt(i);
|
||||
if (details.kind() == kAccessor) return true;
|
||||
}
|
||||
@ -1534,7 +1533,6 @@ class DictionaryElementsAccessor
|
||||
|
||||
static uint32_t FilterKey(Handle<SeededNumberDictionary> dictionary,
|
||||
int entry, Object* raw_key, PropertyFilter filter) {
|
||||
DCHECK(!dictionary->IsDeleted(entry));
|
||||
DCHECK(raw_key->IsNumber());
|
||||
DCHECK_LE(raw_key->Number(), kMaxUInt32);
|
||||
PropertyDetails details = dictionary->DetailsAt(entry);
|
||||
@ -1607,16 +1605,12 @@ class DictionaryElementsAccessor
|
||||
KeyAccumulator* accumulator,
|
||||
AddKeyConversion convert) {
|
||||
Isolate* isolate = accumulator->isolate();
|
||||
Handle<Object> undefined = isolate->factory()->undefined_value();
|
||||
Handle<Object> the_hole = isolate->factory()->the_hole_value();
|
||||
Handle<SeededNumberDictionary> dictionary(
|
||||
SeededNumberDictionary::cast(receiver->elements()), isolate);
|
||||
int capacity = dictionary->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = dictionary->KeyAt(i);
|
||||
if (k == *undefined) continue;
|
||||
if (k == *the_hole) continue;
|
||||
if (dictionary->IsDeleted(i)) continue;
|
||||
if (!dictionary->IsKey(isolate, k)) continue;
|
||||
Object* value = dictionary->ValueAt(i);
|
||||
DCHECK(!value->IsTheHole(isolate));
|
||||
DCHECK(!value->IsAccessorPair());
|
||||
|
@ -1235,11 +1235,9 @@ Handle<Cell> Factory::NewManyClosuresCell(Handle<Object> value) {
|
||||
return cell;
|
||||
}
|
||||
|
||||
Handle<PropertyCell> Factory::NewPropertyCell() {
|
||||
CALL_HEAP_FUNCTION(
|
||||
isolate(),
|
||||
isolate()->heap()->AllocatePropertyCell(),
|
||||
PropertyCell);
|
||||
Handle<PropertyCell> Factory::NewPropertyCell(Handle<Name> name) {
|
||||
CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocatePropertyCell(*name),
|
||||
PropertyCell);
|
||||
}
|
||||
|
||||
|
||||
@ -1850,7 +1848,7 @@ Handle<JSGlobalObject> Factory::NewJSGlobalObject(
|
||||
PropertyDetails d(kAccessor, details.attributes(),
|
||||
PropertyCellType::kMutable);
|
||||
Handle<Name> name(descs->GetKey(i));
|
||||
Handle<PropertyCell> cell = NewPropertyCell();
|
||||
Handle<PropertyCell> cell = NewPropertyCell(name);
|
||||
cell->set_value(descs->GetValue(i));
|
||||
// |dictionary| already contains enough space for all properties.
|
||||
USE(GlobalDictionary::Add(dictionary, name, cell, d));
|
||||
|
@ -371,7 +371,7 @@ class V8_EXPORT_PRIVATE Factory final {
|
||||
|
||||
Handle<Cell> NewCell(Handle<Object> value);
|
||||
|
||||
Handle<PropertyCell> NewPropertyCell();
|
||||
Handle<PropertyCell> NewPropertyCell(Handle<Name> name);
|
||||
|
||||
Handle<WeakCell> NewWeakCell(Handle<HeapObject> value);
|
||||
|
||||
|
@ -2535,7 +2535,8 @@ AllocationResult Heap::AllocateCell(Object* value) {
|
||||
return result;
|
||||
}
|
||||
|
||||
AllocationResult Heap::AllocatePropertyCell() {
|
||||
AllocationResult Heap::AllocatePropertyCell(Name* name) {
|
||||
DCHECK(name->IsUniqueName());
|
||||
int size = PropertyCell::kSize;
|
||||
STATIC_ASSERT(PropertyCell::kSize <= kMaxRegularHeapObjectSize);
|
||||
|
||||
@ -2549,6 +2550,7 @@ AllocationResult Heap::AllocatePropertyCell() {
|
||||
cell->set_dependent_code(DependentCode::cast(empty_fixed_array()),
|
||||
SKIP_WRITE_BARRIER);
|
||||
cell->set_property_details(PropertyDetails(Smi::kZero));
|
||||
cell->set_name(name);
|
||||
cell->set_value(the_hole_value());
|
||||
return result;
|
||||
}
|
||||
@ -2841,15 +2843,15 @@ void Heap::CreateInitialObjects() {
|
||||
script->set_type(Script::TYPE_NATIVE);
|
||||
set_empty_script(*script);
|
||||
|
||||
Handle<PropertyCell> cell = factory->NewPropertyCell();
|
||||
Handle<PropertyCell> cell = factory->NewPropertyCell(factory->empty_string());
|
||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||
set_array_protector(*cell);
|
||||
|
||||
cell = factory->NewPropertyCell();
|
||||
cell = factory->NewPropertyCell(factory->empty_string());
|
||||
cell->set_value(the_hole_value());
|
||||
set_empty_property_cell(*cell);
|
||||
|
||||
cell = factory->NewPropertyCell();
|
||||
cell = factory->NewPropertyCell(factory->empty_string());
|
||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||
set_array_iterator_protector(*cell);
|
||||
|
||||
@ -2861,7 +2863,7 @@ void Heap::CreateInitialObjects() {
|
||||
handle(Smi::FromInt(Isolate::kProtectorValid), isolate()));
|
||||
set_species_protector(*species_cell);
|
||||
|
||||
cell = factory->NewPropertyCell();
|
||||
cell = factory->NewPropertyCell(factory->empty_string());
|
||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||
set_string_length_protector(*cell);
|
||||
|
||||
@ -2869,7 +2871,7 @@ void Heap::CreateInitialObjects() {
|
||||
handle(Smi::FromInt(Isolate::kProtectorValid), isolate()));
|
||||
set_fast_array_iteration_protector(*fast_array_iteration_cell);
|
||||
|
||||
cell = factory->NewPropertyCell();
|
||||
cell = factory->NewPropertyCell(factory->empty_string());
|
||||
cell->set_value(Smi::FromInt(Isolate::kProtectorValid));
|
||||
set_array_buffer_neutering_protector(*cell);
|
||||
|
||||
|
@ -2143,7 +2143,7 @@ class Heap {
|
||||
MUST_USE_RESULT AllocationResult AllocateCell(Object* value);
|
||||
|
||||
// Allocate a tenured JS global property cell initialized with the hole.
|
||||
MUST_USE_RESULT AllocationResult AllocatePropertyCell();
|
||||
MUST_USE_RESULT AllocationResult AllocatePropertyCell(Name* name);
|
||||
|
||||
MUST_USE_RESULT AllocationResult AllocateWeakCell(HeapObject* value);
|
||||
|
||||
|
@ -857,8 +857,7 @@ Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSObject> holder,
|
||||
GlobalDictionary* dict = global->global_dictionary();
|
||||
int number = dict->FindEntry(name);
|
||||
DCHECK_NE(NameDictionary::kNotFound, number);
|
||||
Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(number)),
|
||||
isolate);
|
||||
Handle<PropertyCell> cell(dict->CellAt(number), isolate);
|
||||
return isolate->factory()->NewWeakCell(cell);
|
||||
}
|
||||
return Map::GetOrCreatePrototypeWeakCell(holder, isolate);
|
||||
|
@ -224,9 +224,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
|
||||
|
||||
if (holder->IsJSGlobalObject()) {
|
||||
Handle<GlobalDictionary> dictionary(holder->global_dictionary());
|
||||
Handle<PropertyCell> cell(
|
||||
PropertyCell::cast(dictionary->ValueAt(dictionary_entry())));
|
||||
DCHECK(!cell->IsTheHole(isolate_));
|
||||
Handle<PropertyCell> cell(dictionary->CellAt(dictionary_entry()));
|
||||
property_details_ = cell->property_details();
|
||||
PropertyCell::PrepareForValue(dictionary, dictionary_entry(), value,
|
||||
property_details_);
|
||||
@ -600,8 +598,6 @@ Handle<Object> LookupIterator::FetchValue() const {
|
||||
} else if (holder_->IsJSGlobalObject()) {
|
||||
Handle<JSObject> holder = GetHolder<JSObject>();
|
||||
result = holder->global_dictionary()->ValueAt(number_);
|
||||
DCHECK(result->IsPropertyCell());
|
||||
result = PropertyCell::cast(result)->value();
|
||||
} else if (!holder_->HasFastProperties()) {
|
||||
result = holder_->property_dictionary()->ValueAt(number_);
|
||||
} else if (property_details_.location() == kField) {
|
||||
@ -710,9 +706,8 @@ Handle<FieldType> LookupIterator::GetFieldType() const {
|
||||
Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
|
||||
DCHECK(!IsElement());
|
||||
Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
|
||||
Object* value = holder->global_dictionary()->ValueAt(dictionary_entry());
|
||||
DCHECK(value->IsPropertyCell());
|
||||
return handle(PropertyCell::cast(value), isolate_);
|
||||
return handle(holder->global_dictionary()->CellAt(dictionary_entry()),
|
||||
isolate_);
|
||||
}
|
||||
|
||||
|
||||
@ -751,9 +746,7 @@ void LookupIterator::WriteDataValue(Handle<Object> value,
|
||||
}
|
||||
} else if (holder->IsJSGlobalObject()) {
|
||||
GlobalDictionary* dictionary = JSObject::cast(*holder)->global_dictionary();
|
||||
Object* cell = dictionary->ValueAt(dictionary_entry());
|
||||
DCHECK(cell->IsPropertyCell());
|
||||
PropertyCell::cast(cell)->set_value(*value);
|
||||
dictionary->CellAt(dictionary_entry())->set_value(*value);
|
||||
} else {
|
||||
NameDictionary* dictionary = holder->property_dictionary();
|
||||
dictionary->ValueAtPut(dictionary_entry(), *value);
|
||||
@ -834,8 +827,7 @@ LookupIterator::State LookupIterator::LookupInSpecialHolder(
|
||||
int number = dict->FindEntry(name_);
|
||||
if (number == GlobalDictionary::kNotFound) return NOT_FOUND;
|
||||
number_ = static_cast<uint32_t>(number);
|
||||
DCHECK(dict->ValueAt(number_)->IsPropertyCell());
|
||||
PropertyCell* cell = PropertyCell::cast(dict->ValueAt(number_));
|
||||
PropertyCell* cell = dict->CellAt(number_);
|
||||
if (cell->value()->IsTheHole(isolate_)) return NOT_FOUND;
|
||||
property_details_ = cell->property_details();
|
||||
has_property_ = true;
|
||||
|
@ -646,6 +646,7 @@ bool Object::KeyEquals(Object* second) {
|
||||
}
|
||||
|
||||
bool Object::FilterKey(PropertyFilter filter) {
|
||||
DCHECK(!IsPropertyCell());
|
||||
if (IsSymbol()) {
|
||||
if (filter & SKIP_SYMBOLS) return true;
|
||||
if (Symbol::cast(this)->is_private()) return true;
|
||||
@ -1482,9 +1483,9 @@ Handle<Object> Oddball::ToNumber(Handle<Oddball> input) {
|
||||
|
||||
ACCESSORS(Cell, value, Object, kValueOffset)
|
||||
ACCESSORS(PropertyCell, dependent_code, DependentCode, kDependentCodeOffset)
|
||||
ACCESSORS(PropertyCell, property_details_raw, Object, kDetailsOffset)
|
||||
ACCESSORS(PropertyCell, name, Name, kNameOffset)
|
||||
ACCESSORS(PropertyCell, value, Object, kValueOffset)
|
||||
|
||||
ACCESSORS(PropertyCell, property_details_raw, Object, kDetailsOffset)
|
||||
|
||||
PropertyDetails PropertyCell::property_details() {
|
||||
return PropertyDetails(Smi::cast(property_details_raw()));
|
||||
@ -2579,11 +2580,6 @@ int HashTableBase::ComputeCapacity(int at_least_space_for) {
|
||||
return Max(capacity, kMinCapacity);
|
||||
}
|
||||
|
||||
bool HashTableBase::IsKey(Isolate* isolate, Object* k) {
|
||||
Heap* heap = isolate->heap();
|
||||
return k != heap->the_hole_value() && k != heap->undefined_value();
|
||||
}
|
||||
|
||||
void HashTableBase::SetNumberOfElements(int nof) {
|
||||
set(kNumberOfElementsIndex, Smi::FromInt(nof));
|
||||
}
|
||||
@ -6037,13 +6033,14 @@ bool AccessorPair::IsJSAccessor(Object* obj) {
|
||||
template <typename Derived, typename Shape>
|
||||
void Dictionary<Derived, Shape>::ClearEntry(int entry) {
|
||||
Object* the_hole = this->GetHeap()->the_hole_value();
|
||||
SetEntry(entry, the_hole, the_hole, PropertyDetails::Empty());
|
||||
PropertyDetails details = PropertyDetails::Empty();
|
||||
Derived::cast(this)->SetEntry(entry, the_hole, the_hole, details);
|
||||
}
|
||||
|
||||
template <typename Derived, typename Shape>
|
||||
void Dictionary<Derived, Shape>::SetEntry(int entry, Object* key, Object* value,
|
||||
PropertyDetails details) {
|
||||
STATIC_ASSERT(Dictionary::kEntrySize == 2 || Dictionary::kEntrySize == 3);
|
||||
DCHECK(Dictionary::kEntrySize == 2 || Dictionary::kEntrySize == 3);
|
||||
DCHECK(!key->IsName() || details.dictionary_index() > 0);
|
||||
int index = DerivedHashTable::EntryToIndex(entry);
|
||||
DisallowHeapAllocation no_gc;
|
||||
@ -6053,6 +6050,37 @@ void Dictionary<Derived, Shape>::SetEntry(int entry, Object* key, Object* value,
|
||||
if (Shape::kHasDetails) DetailsAtPut(entry, details);
|
||||
}
|
||||
|
||||
Object* GlobalDictionaryShape::Unwrap(Object* object) {
|
||||
return PropertyCell::cast(object)->name();
|
||||
}
|
||||
|
||||
Name* NameDictionary::NameAt(int entry) { return Name::cast(KeyAt(entry)); }
|
||||
|
||||
PropertyCell* GlobalDictionary::CellAt(int entry) {
|
||||
DCHECK(KeyAt(entry)->IsPropertyCell());
|
||||
return PropertyCell::cast(KeyAt(entry));
|
||||
}
|
||||
|
||||
bool GlobalDictionaryShape::IsLive(Isolate* isolate, Object* k) {
|
||||
Heap* heap = isolate->heap();
|
||||
DCHECK_NE(heap->the_hole_value(), k);
|
||||
return k != heap->undefined_value();
|
||||
}
|
||||
|
||||
bool GlobalDictionaryShape::IsKey(Isolate* isolate, Object* k) {
|
||||
return IsLive(isolate, k) &&
|
||||
!PropertyCell::cast(k)->value()->IsTheHole(isolate);
|
||||
}
|
||||
|
||||
Name* GlobalDictionary::NameAt(int entry) { return CellAt(entry)->name(); }
|
||||
Object* GlobalDictionary::ValueAt(int entry) { return CellAt(entry)->value(); }
|
||||
|
||||
void GlobalDictionary::SetEntry(int entry, Object* key, Object* value,
|
||||
PropertyDetails details) {
|
||||
DCHECK_EQ(key, PropertyCell::cast(value)->name());
|
||||
set(EntryToIndex(entry) + kEntryKeyIndex, value);
|
||||
DetailsAtPut(entry, details);
|
||||
}
|
||||
|
||||
bool NumberDictionaryShape::IsMatch(uint32_t key, Object* other) {
|
||||
DCHECK(other->IsNumber());
|
||||
@ -6105,6 +6133,14 @@ uint32_t NameDictionaryShape::HashForObject(Isolate* isolate, Object* other) {
|
||||
return Name::cast(other)->Hash();
|
||||
}
|
||||
|
||||
bool GlobalDictionaryShape::IsMatch(Handle<Name> key, Object* other) {
|
||||
DCHECK(PropertyCell::cast(other)->name()->IsUniqueName());
|
||||
return *key == PropertyCell::cast(other)->name();
|
||||
}
|
||||
|
||||
uint32_t GlobalDictionaryShape::HashForObject(Isolate* isolate, Object* other) {
|
||||
return PropertyCell::cast(other)->name()->Hash();
|
||||
}
|
||||
|
||||
Handle<Object> NameDictionaryShape::AsHandle(Isolate* isolate,
|
||||
Handle<Name> key) {
|
||||
@ -6116,10 +6152,7 @@ Handle<Object> NameDictionaryShape::AsHandle(Isolate* isolate,
|
||||
template <typename Dictionary>
|
||||
PropertyDetails GlobalDictionaryShape::DetailsAt(Dictionary* dict, int entry) {
|
||||
DCHECK_LE(0, entry); // Not found is -1, which is not caught by get().
|
||||
Object* raw_value = dict->ValueAt(entry);
|
||||
DCHECK(raw_value->IsPropertyCell());
|
||||
PropertyCell* cell = PropertyCell::cast(raw_value);
|
||||
return cell->property_details();
|
||||
return dict->CellAt(entry)->property_details();
|
||||
}
|
||||
|
||||
|
||||
@ -6127,7 +6160,7 @@ template <typename Dictionary>
|
||||
void GlobalDictionaryShape::DetailsAtPut(Dictionary* dict, int entry,
|
||||
PropertyDetails value) {
|
||||
DCHECK_LE(0, entry); // Not found is -1, which is not caught by get().
|
||||
PropertyCell* cell = PropertyCell::cast(dict->ValueAt(entry));
|
||||
PropertyCell* cell = dict->CellAt(entry);
|
||||
if (cell->property_details().IsReadOnly() != value.IsReadOnly()) {
|
||||
cell->dependent_code()->DeoptimizeDependentCodeGroup(
|
||||
cell->GetIsolate(), DependentCode::kPropertyCellChangedGroup);
|
||||
@ -6135,14 +6168,6 @@ void GlobalDictionaryShape::DetailsAtPut(Dictionary* dict, int entry,
|
||||
cell->set_property_details(value);
|
||||
}
|
||||
|
||||
template <typename Dictionary>
|
||||
bool GlobalDictionaryShape::IsDeleted(Dictionary* dict, int entry) {
|
||||
DCHECK(dict->ValueAt(entry)->IsPropertyCell());
|
||||
Isolate* isolate = dict->GetIsolate();
|
||||
return PropertyCell::cast(dict->ValueAt(entry))->value()->IsTheHole(isolate);
|
||||
}
|
||||
|
||||
|
||||
bool ObjectHashTableShape::IsMatch(Handle<Object> key, Object* other) {
|
||||
return key->SameValue(other);
|
||||
}
|
||||
|
@ -1151,6 +1151,8 @@ void Cell::CellPrint(std::ostream& os) { // NOLINT
|
||||
|
||||
void PropertyCell::PropertyCellPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PropertyCell");
|
||||
os << "\n - name: ";
|
||||
name()->NamePrint(os);
|
||||
os << "\n - value: " << Brief(value());
|
||||
os << "\n - details: ";
|
||||
property_details().PrintAsSlowTo(os);
|
||||
|
167
src/objects.cc
167
src/objects.cc
@ -1927,7 +1927,7 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
||||
int entry = dictionary->FindEntry(isolate, name, hash);
|
||||
|
||||
if (entry == GlobalDictionary::kNotFound) {
|
||||
auto cell = isolate->factory()->NewPropertyCell();
|
||||
auto cell = isolate->factory()->NewPropertyCell(name);
|
||||
cell->set_value(*value);
|
||||
auto cell_type = value->IsUndefined(isolate)
|
||||
? PropertyCellType::kUndefined
|
||||
@ -3085,10 +3085,12 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
|
||||
break;
|
||||
}
|
||||
case PROPERTY_CELL_TYPE: {
|
||||
os << "<PropertyCell value=";
|
||||
PropertyCell* cell = PropertyCell::cast(this);
|
||||
os << "<PropertyCell name=";
|
||||
cell->name()->ShortPrint(os);
|
||||
os << " value=";
|
||||
HeapStringAllocator allocator;
|
||||
StringStream accumulator(&allocator);
|
||||
PropertyCell* cell = PropertyCell::cast(this);
|
||||
cell->value()->ShortPrint(&accumulator);
|
||||
os << accumulator.ToCString().get();
|
||||
os << '>';
|
||||
@ -5772,12 +5774,11 @@ void JSObject::MigrateSlowToFast(Handle<JSObject> object,
|
||||
int current_offset = 0;
|
||||
for (int i = 0; i < instance_descriptor_length; i++) {
|
||||
int index = Smi::cast(iteration_order->get(i))->value();
|
||||
Object* k = dictionary->KeyAt(index);
|
||||
DCHECK(dictionary->IsKey(isolate, k));
|
||||
Name* k = dictionary->NameAt(index);
|
||||
// Dictionary keys are internalized upon insertion.
|
||||
// TODO(jkummerow): Turn this into a DCHECK if it's not hit in the wild.
|
||||
CHECK(k->IsUniqueName());
|
||||
Handle<Name> key(Name::cast(k), isolate);
|
||||
Handle<Name> key(k, isolate);
|
||||
|
||||
Object* value = dictionary->ValueAt(index);
|
||||
|
||||
@ -7467,16 +7468,15 @@ Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver,
|
||||
namespace {
|
||||
|
||||
template <typename Dictionary>
|
||||
bool TestDictionaryPropertiesIntegrityLevel(Dictionary dict, Isolate* isolate,
|
||||
bool TestDictionaryPropertiesIntegrityLevel(Dictionary* dict, Isolate* isolate,
|
||||
PropertyAttributes level) {
|
||||
DCHECK(level == SEALED || level == FROZEN);
|
||||
|
||||
uint32_t capacity = dict->Capacity();
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
Object* key = dict->KeyAt(i);
|
||||
if (!dict->IsKey(isolate, key) || key->FilterKey(ALL_PROPERTIES) ||
|
||||
dict->IsDeleted(i))
|
||||
continue;
|
||||
Object* key;
|
||||
if (!dict->ToKey(isolate, i, &key)) continue;
|
||||
if (key->FilterKey(ALL_PROPERTIES)) continue;
|
||||
PropertyDetails details = dict->DetailsAt(i);
|
||||
if (details.IsConfigurable()) return false;
|
||||
if (level == FROZEN && details.kind() == kData && !details.IsReadOnly()) {
|
||||
@ -7777,21 +7777,18 @@ void ApplyAttributesToDictionary(Isolate* isolate,
|
||||
const PropertyAttributes attributes) {
|
||||
int capacity = dictionary->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = dictionary->KeyAt(i);
|
||||
if (dictionary->IsKey(isolate, k) &&
|
||||
!(k->IsSymbol() && Symbol::cast(k)->is_private())) {
|
||||
PropertyDetails details = dictionary->DetailsAt(i);
|
||||
int attrs = attributes;
|
||||
// READ_ONLY is an invalid attribute for JS setters/getters.
|
||||
if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
|
||||
Object* v = dictionary->ValueAt(i);
|
||||
if (v->IsPropertyCell()) v = PropertyCell::cast(v)->value();
|
||||
if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
|
||||
}
|
||||
details = details.CopyAddAttributes(
|
||||
static_cast<PropertyAttributes>(attrs));
|
||||
dictionary->DetailsAtPut(i, details);
|
||||
Object* k;
|
||||
if (!dictionary->ToKey(isolate, i, &k)) continue;
|
||||
if (k->FilterKey(ALL_PROPERTIES)) continue;
|
||||
PropertyDetails details = dictionary->DetailsAt(i);
|
||||
int attrs = attributes;
|
||||
// READ_ONLY is an invalid attribute for JS setters/getters.
|
||||
if ((attributes & READ_ONLY) && details.kind() == kAccessor) {
|
||||
Object* v = dictionary->ValueAt(i);
|
||||
if (v->IsAccessorPair()) attrs &= ~READ_ONLY;
|
||||
}
|
||||
details = details.CopyAddAttributes(static_cast<PropertyAttributes>(attrs));
|
||||
dictionary->DetailsAtPut(i, details);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15523,7 +15520,7 @@ void Dictionary<Derived, Shape>::Print(std::ostream& os) { // NOLINT
|
||||
int capacity = this->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = this->KeyAt(i);
|
||||
if (this->IsKey(isolate, k)) {
|
||||
if (Shape::IsLive(isolate, k)) {
|
||||
os << "\n ";
|
||||
if (k->IsString()) {
|
||||
String::cast(k)->StringPrint(os);
|
||||
@ -16043,7 +16040,7 @@ void HashTable<Derived, Shape>::Rehash(Derived* new_table) {
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
uint32_t from_index = EntryToIndex(i);
|
||||
Object* k = this->get(from_index);
|
||||
if (IsKey(isolate, k)) {
|
||||
if (Shape::IsLive(isolate, k)) {
|
||||
uint32_t hash = Shape::HashForObject(isolate, k);
|
||||
uint32_t insertion_index =
|
||||
EntryToIndex(new_table->FindInsertionEntry(hash));
|
||||
@ -16099,11 +16096,11 @@ void HashTable<Derived, Shape>::Rehash() {
|
||||
done = true;
|
||||
for (uint32_t current = 0; current < capacity; current++) {
|
||||
Object* current_key = KeyAt(current);
|
||||
if (IsKey(isolate, current_key)) {
|
||||
if (Shape::IsLive(isolate, current_key)) {
|
||||
uint32_t target = EntryForProbe(current_key, probe, current);
|
||||
if (current == target) continue;
|
||||
Object* target_key = KeyAt(target);
|
||||
if (!IsKey(isolate, target_key) ||
|
||||
if (!Shape::IsLive(isolate, target_key) ||
|
||||
EntryForProbe(target_key, probe, target) != target) {
|
||||
// Put the current element into the correct position.
|
||||
Swap(current, target, mode);
|
||||
@ -16204,8 +16201,7 @@ uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) {
|
||||
// EnsureCapacity will guarantee the hash table is never full.
|
||||
Isolate* isolate = GetIsolate();
|
||||
while (true) {
|
||||
Object* element = KeyAt(entry);
|
||||
if (!IsKey(isolate, element)) break;
|
||||
if (!Shape::IsLive(isolate, KeyAt(entry))) break;
|
||||
entry = NextProbe(entry, count++, capacity);
|
||||
}
|
||||
return entry;
|
||||
@ -16371,8 +16367,8 @@ Handle<Object> JSObject::PrepareSlowElementsForSort(
|
||||
// allocated one that is large enough for all entries.
|
||||
DisallowHeapAllocation no_gc;
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = dict->KeyAt(i);
|
||||
if (!dict->IsKey(isolate, k)) continue;
|
||||
Object* k;
|
||||
if (!dict->ToKey(isolate, i, &k)) continue;
|
||||
|
||||
DCHECK(k->IsNumber());
|
||||
DCHECK(!k->IsSmi() || Smi::cast(k)->value() >= 0);
|
||||
@ -16782,9 +16778,7 @@ Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
Handle<PropertyCell> cell;
|
||||
if (entry != GlobalDictionary::kNotFound) {
|
||||
if (entry_out) *entry_out = entry;
|
||||
// This call should be idempotent.
|
||||
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
|
||||
cell = handle(PropertyCell::cast(dictionary->ValueAt(entry)));
|
||||
cell = handle(dictionary->CellAt(entry));
|
||||
PropertyCellType original_cell_type = cell->property_details().cell_type();
|
||||
DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
|
||||
original_cell_type == PropertyCellType::kUninitialized);
|
||||
@ -16796,7 +16790,7 @@ Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
cell->set_property_details(details);
|
||||
return cell;
|
||||
}
|
||||
cell = isolate->factory()->NewPropertyCell();
|
||||
cell = isolate->factory()->NewPropertyCell(name);
|
||||
PropertyDetails details(kData, NONE, cell_type);
|
||||
dictionary =
|
||||
GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
|
||||
@ -17606,7 +17600,7 @@ Handle<Derived> Dictionary<Derived, Shape>::Add(Handle<Derived> dictionary,
|
||||
uint32_t entry = dictionary->FindInsertionEntry(hash);
|
||||
dictionary->SetEntry(entry, *k, *value, details);
|
||||
DCHECK(dictionary->KeyAt(entry)->IsNumber() ||
|
||||
dictionary->KeyAt(entry)->IsUniqueName());
|
||||
Shape::Unwrap(dictionary->KeyAt(entry))->IsUniqueName());
|
||||
dictionary->ElementAdded();
|
||||
if (entry_out) *entry_out = entry;
|
||||
return dictionary;
|
||||
@ -17617,9 +17611,8 @@ bool SeededNumberDictionary::HasComplexElements() {
|
||||
Isolate* isolate = this->GetIsolate();
|
||||
int capacity = this->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = this->KeyAt(i);
|
||||
if (!this->IsKey(isolate, k)) continue;
|
||||
DCHECK(!IsDeleted(i));
|
||||
Object* k;
|
||||
if (!this->ToKey(isolate, i, &k)) continue;
|
||||
PropertyDetails details = this->DetailsAt(i);
|
||||
if (details.kind() == kAccessor) return true;
|
||||
PropertyAttributes attr = details.attributes();
|
||||
@ -17666,8 +17659,8 @@ void SeededNumberDictionary::CopyValuesTo(FixedArray* elements) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = this->KeyAt(i);
|
||||
if (this->IsKey(isolate, k)) {
|
||||
Object* k;
|
||||
if (this->ToKey(isolate, i, &k)) {
|
||||
elements->set(pos++, this->ValueAt(i), mode);
|
||||
}
|
||||
}
|
||||
@ -17687,13 +17680,12 @@ int Dictionary<Derived, Shape>::NumberOfEnumerableProperties() {
|
||||
int capacity = this->Capacity();
|
||||
int result = 0;
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = this->KeyAt(i);
|
||||
if (this->IsKey(isolate, k) && !k->FilterKey(ENUMERABLE_STRINGS)) {
|
||||
if (this->IsDeleted(i)) continue;
|
||||
PropertyDetails details = this->DetailsAt(i);
|
||||
PropertyAttributes attr = details.attributes();
|
||||
if ((attr & ONLY_ENUMERABLE) == 0) result++;
|
||||
}
|
||||
Object* k;
|
||||
if (!this->ToKey(isolate, i, &k)) continue;
|
||||
if (k->FilterKey(ENUMERABLE_STRINGS)) continue;
|
||||
PropertyDetails details = this->DetailsAt(i);
|
||||
PropertyAttributes attr = details.attributes();
|
||||
if ((attr & ONLY_ENUMERABLE) == 0) result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -17721,9 +17713,9 @@ void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
|
||||
int capacity = dictionary->Capacity();
|
||||
int properties = 0;
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* key = dictionary->KeyAt(i);
|
||||
Object* key;
|
||||
if (!dictionary->ToKey(isolate, i, &key)) continue;
|
||||
bool is_shadowing_key = false;
|
||||
if (!dictionary->IsKey(isolate, key)) continue;
|
||||
if (key->IsSymbol()) continue;
|
||||
PropertyDetails details = dictionary->DetailsAt(i);
|
||||
if (details.IsDontEnum()) {
|
||||
@ -17733,7 +17725,6 @@ void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (dictionary->IsDeleted(i)) continue;
|
||||
if (is_shadowing_key) {
|
||||
accumulator->AddShadowingKey(key);
|
||||
continue;
|
||||
@ -17757,7 +17748,7 @@ void BaseNameDictionary<Derived, Shape>::CopyEnumKeysTo(
|
||||
std::sort(start, start + length, cmp);
|
||||
for (int i = 0; i < length; i++) {
|
||||
int index = Smi::cast(raw_storage->get(i))->value();
|
||||
raw_storage->set(i, raw_dictionary->KeyAt(index));
|
||||
raw_storage->set(i, raw_dictionary->NameAt(index));
|
||||
}
|
||||
}
|
||||
|
||||
@ -17773,9 +17764,8 @@ Handle<FixedArray> BaseNameDictionary<Derived, Shape>::IterationIndices(
|
||||
DisallowHeapAllocation no_gc;
|
||||
Derived* raw_dictionary = *dictionary;
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = raw_dictionary->KeyAt(i);
|
||||
if (!raw_dictionary->IsKey(isolate, k)) continue;
|
||||
if (raw_dictionary->IsDeleted(i)) continue;
|
||||
Object* k;
|
||||
if (!raw_dictionary->ToKey(isolate, i, &k)) continue;
|
||||
array->set(array_size++, Smi::FromInt(i));
|
||||
}
|
||||
|
||||
@ -17806,9 +17796,9 @@ void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
|
||||
DisallowHeapAllocation no_gc;
|
||||
Derived* raw_dictionary = *dictionary;
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = raw_dictionary->KeyAt(i);
|
||||
if (!raw_dictionary->IsKey(isolate, k) || k->FilterKey(filter)) continue;
|
||||
if (raw_dictionary->IsDeleted(i)) continue;
|
||||
Object* k;
|
||||
if (!raw_dictionary->ToKey(isolate, i, &k)) continue;
|
||||
if (k->FilterKey(filter)) continue;
|
||||
PropertyDetails details = raw_dictionary->DetailsAt(i);
|
||||
if ((details.attributes() & filter) != 0) {
|
||||
keys->AddShadowingKey(k);
|
||||
@ -17817,9 +17807,6 @@ void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
|
||||
if (filter & ONLY_ALL_CAN_READ) {
|
||||
if (details.kind() != kAccessor) continue;
|
||||
Object* accessors = raw_dictionary->ValueAt(i);
|
||||
if (accessors->IsPropertyCell()) {
|
||||
accessors = PropertyCell::cast(accessors)->value();
|
||||
}
|
||||
if (!accessors->IsAccessorInfo()) continue;
|
||||
if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
|
||||
}
|
||||
@ -17838,7 +17825,7 @@ void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
|
||||
bool has_seen_symbol = false;
|
||||
for (int i = 0; i < array_size; i++) {
|
||||
int index = Smi::cast(array->get(i))->value();
|
||||
Object* key = dictionary->KeyAt(index);
|
||||
Object* key = dictionary->NameAt(index);
|
||||
if (key->IsSymbol()) {
|
||||
has_seen_symbol = true;
|
||||
continue;
|
||||
@ -17848,27 +17835,23 @@ void BaseNameDictionary<Derived, Shape>::CollectKeysTo(
|
||||
if (has_seen_symbol) {
|
||||
for (int i = 0; i < array_size; i++) {
|
||||
int index = Smi::cast(array->get(i))->value();
|
||||
Object* key = dictionary->KeyAt(index);
|
||||
Object* key = dictionary->NameAt(index);
|
||||
if (!key->IsSymbol()) continue;
|
||||
keys->AddKey(key, DO_NOT_CONVERT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Backwards lookup (slow).
|
||||
template <typename Derived, typename Shape>
|
||||
Object* Dictionary<Derived, Shape>::SlowReverseLookup(Object* value) {
|
||||
Isolate* isolate = this->GetIsolate();
|
||||
int capacity = this->Capacity();
|
||||
Derived* dictionary = Derived::cast(this);
|
||||
Isolate* isolate = dictionary->GetIsolate();
|
||||
int capacity = dictionary->Capacity();
|
||||
for (int i = 0; i < capacity; i++) {
|
||||
Object* k = this->KeyAt(i);
|
||||
if (!this->IsKey(isolate, k)) continue;
|
||||
Object* e = this->ValueAt(i);
|
||||
// TODO(dcarney): this should be templatized.
|
||||
if (e->IsPropertyCell()) {
|
||||
e = PropertyCell::cast(e)->value();
|
||||
}
|
||||
Object* k;
|
||||
if (!dictionary->ToKey(isolate, i, &k)) continue;
|
||||
Object* e = dictionary->ValueAt(i);
|
||||
if (e == value) return k;
|
||||
}
|
||||
return isolate->heap()->undefined_value();
|
||||
@ -18743,11 +18726,11 @@ Handle<JSArray> JSWeakCollection::GetEntries(Handle<JSWeakCollection> holder,
|
||||
int count = 0;
|
||||
for (int i = 0;
|
||||
count / values_per_entry < max_entries && i < table->Capacity(); i++) {
|
||||
Handle<Object> key(table->KeyAt(i), isolate);
|
||||
if (table->IsKey(isolate, *key)) {
|
||||
entries->set(count++, *key);
|
||||
Object* key;
|
||||
if (table->ToKey(isolate, i, &key)) {
|
||||
entries->set(count++, key);
|
||||
if (values_per_entry > 1) {
|
||||
Object* value = table->Lookup(key);
|
||||
Object* value = table->Lookup(handle(key, isolate));
|
||||
entries->set(count++, value);
|
||||
}
|
||||
}
|
||||
@ -19164,9 +19147,9 @@ Handle<PropertyCell> PropertyCell::InvalidateEntry(
|
||||
Handle<GlobalDictionary> dictionary, int entry) {
|
||||
Isolate* isolate = dictionary->GetIsolate();
|
||||
// Swap with a copy.
|
||||
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
|
||||
Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
|
||||
Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
|
||||
Handle<PropertyCell> cell(dictionary->CellAt(entry));
|
||||
Handle<Name> name(cell->name(), isolate);
|
||||
Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell(name);
|
||||
new_cell->set_value(cell->value());
|
||||
dictionary->ValueAtPut(entry, *new_cell);
|
||||
bool is_the_hole = cell->value()->IsTheHole(isolate);
|
||||
@ -19249,19 +19232,20 @@ Handle<PropertyCell> PropertyCell::PrepareForValue(
|
||||
PropertyDetails details) {
|
||||
Isolate* isolate = dictionary->GetIsolate();
|
||||
DCHECK(!value->IsTheHole(isolate));
|
||||
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
|
||||
Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
|
||||
Handle<PropertyCell> cell(dictionary->CellAt(entry));
|
||||
const PropertyDetails original_details = cell->property_details();
|
||||
// Data accesses could be cached in ics or optimized code.
|
||||
bool invalidate =
|
||||
original_details.kind() == kData && details.kind() == kAccessor;
|
||||
int index = original_details.dictionary_index();
|
||||
int index;
|
||||
PropertyCellType old_type = original_details.cell_type();
|
||||
// Preserve the enumeration index unless the property was deleted or never
|
||||
// initialized.
|
||||
if (cell->value()->IsTheHole(isolate)) {
|
||||
index = dictionary->NextEnumerationIndex();
|
||||
dictionary->SetNextEnumerationIndex(index + 1);
|
||||
} else {
|
||||
index = original_details.dictionary_index();
|
||||
}
|
||||
DCHECK_LT(0, index);
|
||||
details = details.set_index(index);
|
||||
@ -19879,9 +19863,9 @@ void FetchStarExports(Handle<Module> module, Zone* zone,
|
||||
Handle<ObjectHashTable> requested_exports(requested_module->exports(),
|
||||
isolate);
|
||||
for (int i = 0, n = requested_exports->Capacity(); i < n; ++i) {
|
||||
Handle<Object> key(requested_exports->KeyAt(i), isolate);
|
||||
if (!requested_exports->IsKey(isolate, *key)) continue;
|
||||
Handle<String> name = Handle<String>::cast(key);
|
||||
Object* key;
|
||||
if (!requested_exports->ToKey(isolate, i, &key)) continue;
|
||||
Handle<String> name(String::cast(key), isolate);
|
||||
|
||||
if (name->Equals(isolate->heap()->default_string())) continue;
|
||||
if (!exports->Lookup(name)->IsTheHole(isolate)) continue;
|
||||
@ -19945,10 +19929,9 @@ Handle<JSModuleNamespace> Module::GetModuleNamespace(Handle<Module> module) {
|
||||
ZoneVector<Handle<String>> names(&zone);
|
||||
names.reserve(exports->NumberOfElements());
|
||||
for (int i = 0, n = exports->Capacity(); i < n; ++i) {
|
||||
Handle<Object> key(exports->KeyAt(i), isolate);
|
||||
if (!exports->IsKey(isolate, *key)) continue;
|
||||
DCHECK(exports->ValueAt(i)->IsCell());
|
||||
names.push_back(Handle<String>::cast(key));
|
||||
Object* key;
|
||||
if (!exports->ToKey(isolate, i, &key)) continue;
|
||||
names.push_back(handle(String::cast(key), isolate));
|
||||
}
|
||||
DCHECK_EQ(static_cast<int>(names.size()), exports->NumberOfElements());
|
||||
|
||||
|
@ -6043,6 +6043,8 @@ class Cell: public HeapObject {
|
||||
|
||||
class PropertyCell : public HeapObject {
|
||||
public:
|
||||
// [name]: the name of the global property.
|
||||
DECL_ACCESSORS(name, Name)
|
||||
// [property_details]: details of the global property.
|
||||
DECL_ACCESSORS(property_details_raw, Object)
|
||||
// [value]: value of the global property.
|
||||
@ -6082,13 +6084,12 @@ class PropertyCell : public HeapObject {
|
||||
|
||||
// Layout description.
|
||||
static const int kDetailsOffset = HeapObject::kHeaderSize;
|
||||
static const int kValueOffset = kDetailsOffset + kPointerSize;
|
||||
static const int kNameOffset = kDetailsOffset + kPointerSize;
|
||||
static const int kValueOffset = kNameOffset + kPointerSize;
|
||||
static const int kDependentCodeOffset = kValueOffset + kPointerSize;
|
||||
static const int kSize = kDependentCodeOffset + kPointerSize;
|
||||
|
||||
typedef FixedBodyDescriptor<kValueOffset,
|
||||
kSize,
|
||||
kSize> BodyDescriptor;
|
||||
typedef FixedBodyDescriptor<kNameOffset, kSize, kSize> BodyDescriptor;
|
||||
// No weak fields.
|
||||
typedef BodyDescriptor BodyDescriptorWeak;
|
||||
|
||||
|
@ -47,11 +47,6 @@ class Dictionary : public HashTable<Derived, Shape> {
|
||||
Shape::DetailsAtPut(static_cast<Derived*>(this), entry, value);
|
||||
}
|
||||
|
||||
// Returns true if property at given entry is deleted.
|
||||
bool IsDeleted(int entry) {
|
||||
return Shape::IsDeleted(static_cast<Derived*>(this), entry);
|
||||
}
|
||||
|
||||
// Delete a property from the dictionary.
|
||||
MUST_USE_RESULT static Handle<Derived> DeleteEntry(Handle<Derived> dictionary,
|
||||
int entry);
|
||||
@ -109,11 +104,6 @@ class BaseDictionaryShape : public BaseShape<Key> {
|
||||
dict->set(Dictionary::EntryToIndex(entry) + Dictionary::kEntryDetailsIndex,
|
||||
value.AsSmi());
|
||||
}
|
||||
|
||||
template <typename Dictionary>
|
||||
static bool IsDeleted(Dictionary* dict, int entry) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class NameDictionaryShape : public BaseDictionaryShape<Handle<Name>> {
|
||||
@ -181,11 +171,15 @@ class NameDictionary
|
||||
|
||||
static const int kEntryDetailsIndex = 2;
|
||||
static const int kInitialCapacity = 2;
|
||||
inline Name* NameAt(int entry);
|
||||
};
|
||||
|
||||
class GlobalDictionaryShape : public NameDictionaryShape {
|
||||
public:
|
||||
static const int kEntrySize = 2; // Overrides NameDictionaryShape::kEntrySize
|
||||
static inline bool IsMatch(Handle<Name> key, Object* other);
|
||||
static inline uint32_t HashForObject(Isolate* isolate, Object* object);
|
||||
|
||||
static const int kEntrySize = 1; // Overrides NameDictionaryShape::kEntrySize
|
||||
|
||||
template <typename Dictionary>
|
||||
static inline PropertyDetails DetailsAt(Dictionary* dict, int entry);
|
||||
@ -194,14 +188,22 @@ class GlobalDictionaryShape : public NameDictionaryShape {
|
||||
static inline void DetailsAtPut(Dictionary* dict, int entry,
|
||||
PropertyDetails value);
|
||||
|
||||
template <typename Dictionary>
|
||||
static bool IsDeleted(Dictionary* dict, int entry);
|
||||
static inline Object* Unwrap(Object* key);
|
||||
static inline bool IsKey(Isolate* isolate, Object* k);
|
||||
static inline bool IsLive(Isolate* isolate, Object* key);
|
||||
};
|
||||
|
||||
class GlobalDictionary
|
||||
: public BaseNameDictionary<GlobalDictionary, GlobalDictionaryShape> {
|
||||
public:
|
||||
DECLARE_CAST(GlobalDictionary)
|
||||
|
||||
inline Object* ValueAt(int entry);
|
||||
inline PropertyCell* CellAt(int entry);
|
||||
inline void SetEntry(int entry, Object* key, Object* value,
|
||||
PropertyDetails details);
|
||||
inline Name* NameAt(int entry);
|
||||
void ValueAtPut(int entry, Object* value) { set(EntryToIndex(entry), value); }
|
||||
};
|
||||
|
||||
class NumberDictionaryShape : public BaseDictionaryShape<uint32_t> {
|
||||
|
@ -10,6 +10,12 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
template <typename KeyT>
|
||||
bool BaseShape<KeyT>::IsLive(Isolate* isolate, Object* k) {
|
||||
Heap* heap = isolate->heap();
|
||||
return k != heap->the_hole_value() && k != heap->undefined_value();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -58,6 +58,11 @@ class BaseShape {
|
||||
typedef KeyT Key;
|
||||
static inline Map* GetMap(Isolate* isolate);
|
||||
static const bool kNeedsHoleCheck = true;
|
||||
static Object* Unwrap(Object* key) { return key; }
|
||||
static bool IsKey(Isolate* isolate, Object* key) {
|
||||
return IsLive(isolate, key);
|
||||
}
|
||||
static inline bool IsLive(Isolate* isolate, Object* key);
|
||||
};
|
||||
|
||||
class V8_EXPORT_PRIVATE HashTableBase : public NON_EXPORTED_BASE(FixedArray) {
|
||||
@ -84,10 +89,6 @@ class V8_EXPORT_PRIVATE HashTableBase : public NON_EXPORTED_BASE(FixedArray) {
|
||||
// number of elements. May be more than HashTable::kMaxCapacity.
|
||||
static inline int ComputeCapacity(int at_least_space_for);
|
||||
|
||||
// Tells whether k is a real key. The hole and undefined are not allowed
|
||||
// as keys and can be used to indicate missing or deleted elements.
|
||||
static inline bool IsKey(Isolate* isolate, Object* k);
|
||||
|
||||
// Compute the probe offset (quadratic probing).
|
||||
INLINE(static uint32_t GetProbeOffset(uint32_t n)) {
|
||||
return (n + n * n) >> 1;
|
||||
@ -153,6 +154,19 @@ class HashTable : public HashTableBase {
|
||||
// Rehashes the table in-place.
|
||||
void Rehash();
|
||||
|
||||
// Tells whether k is a real key. The hole and undefined are not allowed
|
||||
// as keys and can be used to indicate missing or deleted elements.
|
||||
static bool IsKey(Isolate* isolate, Object* k) {
|
||||
return Shape::IsKey(isolate, k);
|
||||
}
|
||||
|
||||
inline bool ToKey(Isolate* isolate, int entry, Object** out_k) {
|
||||
Object* k = KeyAt(entry);
|
||||
if (!IsKey(isolate, k)) return false;
|
||||
*out_k = Shape::Unwrap(k);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns the key at entry.
|
||||
Object* KeyAt(int entry) { return get(EntryToIndex(entry) + kEntryKeyIndex); }
|
||||
|
||||
|
@ -1575,14 +1575,13 @@ void V8HeapExplorer::ExtractPropertyReferences(JSObject* js_obj, int entry) {
|
||||
GlobalDictionary* dictionary = js_obj->global_dictionary();
|
||||
int length = dictionary->Capacity();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
Object* k = dictionary->KeyAt(i);
|
||||
if (dictionary->IsKey(isolate, k)) {
|
||||
DCHECK(dictionary->ValueAt(i)->IsPropertyCell());
|
||||
PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(i));
|
||||
if (dictionary->IsKey(isolate, dictionary->KeyAt(i))) {
|
||||
PropertyCell* cell = dictionary->CellAt(i);
|
||||
Name* name = cell->name();
|
||||
Object* value = cell->value();
|
||||
PropertyDetails details = cell->property_details();
|
||||
SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry,
|
||||
Name::cast(k), value);
|
||||
SetDataOrAccessorPropertyReference(details.kind(), js_obj, entry, name,
|
||||
value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -70,8 +70,7 @@ static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate,
|
||||
GlobalDictionary* dictionary = receiver->global_dictionary();
|
||||
int entry = dictionary->FindEntry(key);
|
||||
if (entry != GlobalDictionary::kNotFound) {
|
||||
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
|
||||
PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry));
|
||||
PropertyCell* cell = dictionary->CellAt(entry);
|
||||
if (cell->property_details().kind() == kData) {
|
||||
Object* value = cell->value();
|
||||
if (!value->IsTheHole(isolate)) {
|
||||
|
@ -577,7 +577,7 @@ void TestNameDictionaryLookup() {
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < arraysize(keys); i++) {
|
||||
Handle<Object> value = factory->NewPropertyCell();
|
||||
Handle<Object> value = factory->NewPropertyCell(keys[i]);
|
||||
dictionary = Dictionary::Add(dictionary, keys[i], value, fake_details);
|
||||
}
|
||||
|
||||
|
@ -297,17 +297,17 @@ KNOWN_OBJECTS = {
|
||||
("OLD_SPACE", 0x02821): "EmptySloppyArgumentsElements",
|
||||
("OLD_SPACE", 0x02841): "EmptySlowElementDictionary",
|
||||
("OLD_SPACE", 0x02889): "EmptyPropertyCell",
|
||||
("OLD_SPACE", 0x028a9): "EmptyWeakCell",
|
||||
("OLD_SPACE", 0x028c1): "ArrayProtector",
|
||||
("OLD_SPACE", 0x028e1): "IsConcatSpreadableProtector",
|
||||
("OLD_SPACE", 0x028f1): "SpeciesProtector",
|
||||
("OLD_SPACE", 0x02901): "StringLengthProtector",
|
||||
("OLD_SPACE", 0x02921): "FastArrayIterationProtector",
|
||||
("OLD_SPACE", 0x02931): "ArrayIteratorProtector",
|
||||
("OLD_SPACE", 0x02951): "ArrayBufferNeuteringProtector",
|
||||
("OLD_SPACE", 0x02971): "InfinityValue",
|
||||
("OLD_SPACE", 0x02981): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x02991): "MinusInfinityValue",
|
||||
("OLD_SPACE", 0x028b1): "EmptyWeakCell",
|
||||
("OLD_SPACE", 0x028c9): "ArrayProtector",
|
||||
("OLD_SPACE", 0x028f1): "IsConcatSpreadableProtector",
|
||||
("OLD_SPACE", 0x02901): "SpeciesProtector",
|
||||
("OLD_SPACE", 0x02911): "StringLengthProtector",
|
||||
("OLD_SPACE", 0x02939): "FastArrayIterationProtector",
|
||||
("OLD_SPACE", 0x02949): "ArrayIteratorProtector",
|
||||
("OLD_SPACE", 0x02971): "ArrayBufferNeuteringProtector",
|
||||
("OLD_SPACE", 0x02999): "InfinityValue",
|
||||
("OLD_SPACE", 0x029a9): "MinusZeroValue",
|
||||
("OLD_SPACE", 0x029b9): "MinusInfinityValue",
|
||||
}
|
||||
|
||||
# List of known V8 Frame Markers.
|
||||
|
Loading…
Reference in New Issue
Block a user