[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:
Toon Verwaest 2017-06-27 13:57:13 +02:00 committed by Commit Bot
parent 189c8263e5
commit e91c6dc7a9
21 changed files with 235 additions and 205 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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