[runtime] Better encapsulation of dictionary objects handling in lookup iterator.
Now LookupIterator follows the same pattern of prepare transition, apply transition and write value when adding new properties to dictionary objects. JSGlobalObject case: * Prepare transition phase ensures that there is a "transition" property cell prepared for receiving a value. * Apply transition phase does nothing. * Prepare for data property phase ensures that the existing property cell can receive the value. * Write value phase writes value directly to the current property cell. JSObject case: * Prepare transition phase prepares the object for receiving a data value (which could switch an object to dictionary mode). * Apply transition phase migrates object to a transition map. If the map happened to be a dictionary mode object's map then an uninitialized entry added to the properties dictionary. * Prepare for data property phase does nothing. * Write value phase just puts value to the properties dictionary. BUG=chromium:576312 Review-Url: https://codereview.chromium.org/2127583002 Cr-Commit-Position: refs/heads/master@{#37585}
This commit is contained in:
parent
07612e0d35
commit
3fbb45216d
@ -203,7 +203,8 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -109,7 +109,8 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -236,7 +236,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -1755,11 +1755,10 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
|
||||
case LookupIterator::TRANSITION: {
|
||||
auto store_target = lookup->GetStoreTarget();
|
||||
if (store_target->IsJSGlobalObject()) {
|
||||
// TODO(dcarney): this currently just deopts. Use the transition cell.
|
||||
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
|
||||
auto cell = isolate()->factory()->NewPropertyCell();
|
||||
Handle<PropertyCell> cell = lookup->transition_cell();
|
||||
cell->set_value(*value);
|
||||
auto code = PropertyCellStoreHandler(
|
||||
Handle<Code> code = PropertyCellStoreHandler(
|
||||
isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
|
||||
lookup->name(), cell, PropertyCellType::kConstant);
|
||||
cell->set_value(isolate()->heap()->the_hole_value());
|
||||
|
@ -195,7 +195,8 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -195,7 +195,8 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -198,7 +198,8 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -187,7 +187,8 @@ void NamedLoadHandlerCompiler::GenerateLoadFunctionPrototype(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -219,7 +219,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
@ -236,7 +236,8 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
|
||||
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
|
||||
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
Register scratch, Label* miss) {
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsurePropertyCell(global, name);
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name, PropertyCellType::kInvalidated);
|
||||
Isolate* isolate = masm->isolate();
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
Handle<WeakCell> weak_cell = isolate->factory()->NewWeakCell(cell);
|
||||
|
113
src/lookup.cc
113
src/lookup.cc
@ -220,6 +220,16 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (holder->IsJSGlobalObject()) {
|
||||
Handle<GlobalDictionary> dictionary(holder->global_dictionary());
|
||||
Handle<PropertyCell> cell(
|
||||
PropertyCell::cast(dictionary->ValueAt(dictionary_entry())));
|
||||
DCHECK(!cell->IsTheHole(isolate_));
|
||||
property_details_ = cell->property_details();
|
||||
PropertyCell::PrepareForValue(dictionary, dictionary_entry(), value,
|
||||
property_details_);
|
||||
return;
|
||||
}
|
||||
if (!holder->HasFastProperties()) return;
|
||||
|
||||
Handle<Map> old_map(holder->map(), isolate_);
|
||||
@ -252,20 +262,34 @@ void LookupIterator::ReconfigureDataProperty(Handle<Object> value,
|
||||
holder->GetElementsAccessor()->Reconfigure(holder, elements, number_, value,
|
||||
attributes);
|
||||
ReloadPropertyInformation<true>();
|
||||
} else {
|
||||
if (!holder->HasFastProperties()) {
|
||||
PropertyDetails details(attributes, v8::internal::DATA, 0,
|
||||
PropertyCellType::kMutable);
|
||||
JSObject::SetNormalizedProperty(holder, name(), value, details);
|
||||
} else {
|
||||
Handle<Map> old_map(holder->map(), isolate_);
|
||||
Handle<Map> new_map = Map::ReconfigureExistingProperty(
|
||||
old_map, descriptor_number(), i::kData, attributes);
|
||||
new_map =
|
||||
Map::PrepareForDataProperty(new_map, descriptor_number(), value);
|
||||
JSObject::MigrateToMap(holder, new_map);
|
||||
}
|
||||
} else if (holder->HasFastProperties()) {
|
||||
Handle<Map> old_map(holder->map(), isolate_);
|
||||
Handle<Map> new_map = Map::ReconfigureExistingProperty(
|
||||
old_map, descriptor_number(), i::kData, attributes);
|
||||
new_map = Map::PrepareForDataProperty(new_map, descriptor_number(), value);
|
||||
JSObject::MigrateToMap(holder, new_map);
|
||||
ReloadPropertyInformation<false>();
|
||||
} else {
|
||||
PropertyDetails details(attributes, v8::internal::DATA, 0,
|
||||
PropertyCellType::kMutable);
|
||||
if (holder->IsJSGlobalObject()) {
|
||||
Handle<GlobalDictionary> dictionary(holder->global_dictionary());
|
||||
|
||||
Handle<PropertyCell> cell = PropertyCell::PrepareForValue(
|
||||
dictionary, dictionary_entry(), value, details);
|
||||
cell->set_value(*value);
|
||||
property_details_ = cell->property_details();
|
||||
} else {
|
||||
Handle<NameDictionary> dictionary(holder->property_dictionary());
|
||||
PropertyDetails original_details =
|
||||
dictionary->DetailsAt(dictionary_entry());
|
||||
int enumeration_index = original_details.dictionary_index();
|
||||
DCHECK(enumeration_index > 0);
|
||||
details = details.set_index(enumeration_index);
|
||||
dictionary->SetEntry(dictionary_entry(), name(), value, details);
|
||||
property_details_ = details;
|
||||
}
|
||||
state_ = DATA;
|
||||
}
|
||||
|
||||
WriteDataValue(value);
|
||||
@ -297,11 +321,31 @@ void LookupIterator::PrepareTransitionToDataProperty(
|
||||
state_ = TRANSITION;
|
||||
if (map->IsJSGlobalObjectMap()) {
|
||||
// Install a property cell.
|
||||
auto cell = JSGlobalObject::EnsurePropertyCell(
|
||||
Handle<JSGlobalObject>::cast(receiver), name());
|
||||
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(receiver);
|
||||
int entry;
|
||||
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
global, name(), PropertyCellType::kUninitialized, &entry);
|
||||
Handle<GlobalDictionary> dictionary(global->global_dictionary(),
|
||||
isolate_);
|
||||
DCHECK(cell->value()->IsTheHole(isolate_));
|
||||
DCHECK(!value->IsTheHole(isolate_));
|
||||
transition_ = cell;
|
||||
// Assign an enumeration index to the property and update
|
||||
// SetNextEnumerationIndex.
|
||||
int index = dictionary->NextEnumerationIndex();
|
||||
dictionary->SetNextEnumerationIndex(index + 1);
|
||||
property_details_ = PropertyDetails(attributes, i::DATA, index,
|
||||
PropertyCellType::kUninitialized);
|
||||
PropertyCellType new_type =
|
||||
PropertyCell::UpdatedType(cell, value, property_details_);
|
||||
property_details_ = property_details_.set_cell_type(new_type);
|
||||
cell->set_property_details(property_details_);
|
||||
number_ = entry;
|
||||
has_property_ = true;
|
||||
} else {
|
||||
// Don't set enumeration index (it will be set during value store).
|
||||
property_details_ =
|
||||
PropertyDetails(attributes, i::DATA, 0, PropertyCellType::kNoCell);
|
||||
transition_ = map;
|
||||
}
|
||||
return;
|
||||
@ -322,9 +366,11 @@ void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) {
|
||||
DCHECK_EQ(TRANSITION, state_);
|
||||
|
||||
DCHECK(receiver.is_identical_to(GetStoreTarget()));
|
||||
|
||||
if (receiver->IsJSGlobalObject()) return;
|
||||
holder_ = receiver;
|
||||
if (receiver->IsJSGlobalObject()) {
|
||||
state_ = DATA;
|
||||
return;
|
||||
}
|
||||
Handle<Map> transition = transition_map();
|
||||
bool simple_transition = transition->GetBackPointer() == receiver->map();
|
||||
JSObject::MigrateToMap(receiver, transition);
|
||||
@ -334,6 +380,20 @@ void LookupIterator::ApplyTransitionToDataProperty(Handle<JSObject> receiver) {
|
||||
number_ = static_cast<uint32_t>(number);
|
||||
property_details_ = transition->GetLastDescriptorDetails();
|
||||
state_ = DATA;
|
||||
} else if (receiver->map()->is_dictionary_map()) {
|
||||
Handle<NameDictionary> dictionary(receiver->property_dictionary(),
|
||||
isolate_);
|
||||
int entry;
|
||||
dictionary = NameDictionary::Add(dictionary, name(),
|
||||
isolate_->factory()->uninitialized_value(),
|
||||
property_details_, &entry);
|
||||
receiver->set_properties(*dictionary);
|
||||
// Reload details containing proper enumeration index value.
|
||||
property_details_ = dictionary->DetailsAt(entry);
|
||||
number_ = entry;
|
||||
has_property_ = true;
|
||||
state_ = DATA;
|
||||
|
||||
} else {
|
||||
ReloadPropertyInformation<false>();
|
||||
}
|
||||
@ -572,11 +632,10 @@ Handle<FieldType> LookupIterator::GetFieldType() const {
|
||||
|
||||
Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
|
||||
DCHECK(!IsElement());
|
||||
Handle<JSObject> holder = GetHolder<JSObject>();
|
||||
Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
|
||||
Object* value = global->global_dictionary()->ValueAt(dictionary_entry());
|
||||
Handle<JSGlobalObject> holder = GetHolder<JSGlobalObject>();
|
||||
Object* value = holder->global_dictionary()->ValueAt(dictionary_entry());
|
||||
DCHECK(value->IsPropertyCell());
|
||||
return handle(PropertyCell::cast(value));
|
||||
return handle(PropertyCell::cast(value), isolate_);
|
||||
}
|
||||
|
||||
|
||||
@ -608,13 +667,13 @@ void LookupIterator::WriteDataValue(Handle<Object> value) {
|
||||
DCHECK_EQ(v8::internal::DATA_CONSTANT, property_details_.type());
|
||||
}
|
||||
} else if (holder->IsJSGlobalObject()) {
|
||||
Handle<GlobalDictionary> property_dictionary =
|
||||
handle(JSObject::cast(*holder)->global_dictionary());
|
||||
PropertyCell::UpdateCell(property_dictionary, dictionary_entry(), value,
|
||||
property_details_);
|
||||
GlobalDictionary* dictionary = JSObject::cast(*holder)->global_dictionary();
|
||||
Object* cell = dictionary->ValueAt(dictionary_entry());
|
||||
DCHECK(cell->IsPropertyCell());
|
||||
PropertyCell::cast(cell)->set_value(*value);
|
||||
} else {
|
||||
NameDictionary* property_dictionary = holder->property_dictionary();
|
||||
property_dictionary->ValueAtPut(dictionary_entry(), *value);
|
||||
NameDictionary* dictionary = holder->property_dictionary();
|
||||
dictionary->ValueAtPut(dictionary_entry(), *value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,6 +190,10 @@ class LookupIterator final BASE_EMBEDDED {
|
||||
DCHECK_EQ(TRANSITION, state_);
|
||||
return Handle<Map>::cast(transition_);
|
||||
}
|
||||
Handle<PropertyCell> transition_cell() const {
|
||||
DCHECK_EQ(TRANSITION, state_);
|
||||
return Handle<PropertyCell>::cast(transition_);
|
||||
}
|
||||
template <class T>
|
||||
Handle<T> GetHolder() const {
|
||||
DCHECK(IsFound());
|
||||
|
@ -995,6 +995,46 @@ void PropertyCell::PropertyCellPrint(std::ostream& os) { // NOLINT
|
||||
HeapObject::PrintHeader(os, "PropertyCell");
|
||||
os << "\n - value: " << Brief(value());
|
||||
os << "\n - details: " << property_details();
|
||||
PropertyCellType cell_type = property_details().cell_type();
|
||||
os << "\n - cell_type: ";
|
||||
if (value()->IsTheHole(GetIsolate())) {
|
||||
switch (cell_type) {
|
||||
case PropertyCellType::kUninitialized:
|
||||
os << "Uninitialized";
|
||||
break;
|
||||
case PropertyCellType::kInvalidated:
|
||||
os << "Invalidated";
|
||||
break;
|
||||
default:
|
||||
os << "??? " << static_cast<int>(cell_type);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (cell_type) {
|
||||
case PropertyCellType::kUndefined:
|
||||
os << "Undefined";
|
||||
break;
|
||||
case PropertyCellType::kConstant:
|
||||
os << "Constant";
|
||||
break;
|
||||
case PropertyCellType::kConstantType:
|
||||
os << "ConstantType"
|
||||
<< " (";
|
||||
switch (GetConstantType()) {
|
||||
case PropertyCellConstantType::kSmi:
|
||||
os << "Smi";
|
||||
break;
|
||||
case PropertyCellConstantType::kStableMap:
|
||||
os << "StableMap";
|
||||
break;
|
||||
}
|
||||
os << ")";
|
||||
break;
|
||||
case PropertyCellType::kMutable:
|
||||
os << "Mutable";
|
||||
break;
|
||||
}
|
||||
}
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
|
187
src/objects.cc
187
src/objects.cc
@ -1607,9 +1607,9 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
||||
}
|
||||
|
||||
if (object->IsJSGlobalObject()) {
|
||||
Handle<GlobalDictionary> property_dictionary(object->global_dictionary());
|
||||
Handle<GlobalDictionary> dictionary(object->global_dictionary());
|
||||
|
||||
int entry = property_dictionary->FindEntry(name);
|
||||
int entry = dictionary->FindEntry(name);
|
||||
if (entry == GlobalDictionary::kNotFound) {
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
auto cell = isolate->factory()->NewPropertyCell();
|
||||
@ -1619,26 +1619,26 @@ void JSObject::SetNormalizedProperty(Handle<JSObject> object,
|
||||
: PropertyCellType::kConstant;
|
||||
details = details.set_cell_type(cell_type);
|
||||
value = cell;
|
||||
property_dictionary =
|
||||
GlobalDictionary::Add(property_dictionary, name, value, details);
|
||||
object->set_properties(*property_dictionary);
|
||||
dictionary = GlobalDictionary::Add(dictionary, name, value, details);
|
||||
object->set_properties(*dictionary);
|
||||
} else {
|
||||
PropertyCell::UpdateCell(property_dictionary, entry, value, details);
|
||||
Handle<PropertyCell> cell =
|
||||
PropertyCell::PrepareForValue(dictionary, entry, value, details);
|
||||
cell->set_value(*value);
|
||||
}
|
||||
} else {
|
||||
Handle<NameDictionary> property_dictionary(object->property_dictionary());
|
||||
Handle<NameDictionary> dictionary(object->property_dictionary());
|
||||
|
||||
int entry = property_dictionary->FindEntry(name);
|
||||
int entry = dictionary->FindEntry(name);
|
||||
if (entry == NameDictionary::kNotFound) {
|
||||
property_dictionary =
|
||||
NameDictionary::Add(property_dictionary, name, value, details);
|
||||
object->set_properties(*property_dictionary);
|
||||
dictionary = NameDictionary::Add(dictionary, name, value, details);
|
||||
object->set_properties(*dictionary);
|
||||
} else {
|
||||
PropertyDetails original_details = property_dictionary->DetailsAt(entry);
|
||||
PropertyDetails original_details = dictionary->DetailsAt(entry);
|
||||
int enumeration_index = original_details.dictionary_index();
|
||||
DCHECK(enumeration_index > 0);
|
||||
details = details.set_index(enumeration_index);
|
||||
property_dictionary->SetEntry(entry, name, value, details);
|
||||
dictionary->SetEntry(entry, name, value, details);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2849,51 +2849,6 @@ MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
|
||||
return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
|
||||
}
|
||||
|
||||
|
||||
void JSObject::AddSlowProperty(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes) {
|
||||
DCHECK(!object->HasFastProperties());
|
||||
Isolate* isolate = object->GetIsolate();
|
||||
if (object->IsJSGlobalObject()) {
|
||||
Handle<GlobalDictionary> dict(object->global_dictionary());
|
||||
PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
|
||||
int entry = dict->FindEntry(name);
|
||||
// If there's a cell there, just invalidate and set the property.
|
||||
if (entry != GlobalDictionary::kNotFound) {
|
||||
PropertyCell::UpdateCell(dict, entry, value, details);
|
||||
// TODO(ishell): move this to UpdateCell.
|
||||
// Need to adjust the details.
|
||||
int index = dict->NextEnumerationIndex();
|
||||
dict->SetNextEnumerationIndex(index + 1);
|
||||
PropertyCell* cell = PropertyCell::cast(dict->ValueAt(entry));
|
||||
details = cell->property_details().set_index(index);
|
||||
cell->set_property_details(details);
|
||||
|
||||
} else {
|
||||
auto cell = isolate->factory()->NewPropertyCell();
|
||||
cell->set_value(*value);
|
||||
auto cell_type = value->IsUndefined(isolate)
|
||||
? PropertyCellType::kUndefined
|
||||
: PropertyCellType::kConstant;
|
||||
details = details.set_cell_type(cell_type);
|
||||
value = cell;
|
||||
|
||||
Handle<GlobalDictionary> result =
|
||||
GlobalDictionary::Add(dict, name, value, details);
|
||||
if (*dict != *result) object->set_properties(*result);
|
||||
}
|
||||
} else {
|
||||
Handle<NameDictionary> dict(object->property_dictionary());
|
||||
PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
|
||||
Handle<NameDictionary> result =
|
||||
NameDictionary::Add(dict, name, value, details);
|
||||
if (*dict != *result) object->set_properties(*result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* Representation::Mnemonic() const {
|
||||
switch (kind_) {
|
||||
case kNone: return "v";
|
||||
@ -4744,14 +4699,8 @@ Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value,
|
||||
DCHECK_EQ(LookupIterator::TRANSITION, it->state());
|
||||
it->ApplyTransitionToDataProperty(receiver);
|
||||
|
||||
// TODO(verwaest): Encapsulate dictionary handling better.
|
||||
if (receiver->map()->is_dictionary_map()) {
|
||||
// TODO(dcarney): just populate TransitionPropertyCell here?
|
||||
JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
|
||||
} else {
|
||||
// Write the property value.
|
||||
it->WriteDataValue(value);
|
||||
}
|
||||
// Write the property value.
|
||||
it->WriteDataValue(value);
|
||||
|
||||
#if VERIFY_HEAP
|
||||
if (FLAG_verify_heap) {
|
||||
@ -6088,9 +6037,8 @@ void JSReceiver::DeleteNormalizedProperty(Handle<JSReceiver> object,
|
||||
|
||||
auto cell = PropertyCell::InvalidateEntry(dictionary, entry);
|
||||
cell->set_value(isolate->heap()->the_hole_value());
|
||||
// TODO(ishell): InvalidateForDelete
|
||||
cell->set_property_details(
|
||||
cell->property_details().set_cell_type(PropertyCellType::kInvalidated));
|
||||
PropertyDetails::Empty(PropertyCellType::kUninitialized));
|
||||
} else {
|
||||
Handle<NameDictionary> dictionary(object->property_dictionary());
|
||||
DCHECK_NE(NameDictionary::kNotFound, entry);
|
||||
@ -16508,13 +16456,14 @@ template Handle<UnseededNumberDictionary>
|
||||
uint32_t>::Shrink(Handle<UnseededNumberDictionary>, uint32_t);
|
||||
|
||||
template Handle<NameDictionary>
|
||||
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name> >::Add(
|
||||
Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails);
|
||||
Dictionary<NameDictionary, NameDictionaryShape, Handle<Name>>::Add(
|
||||
Handle<NameDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
|
||||
int*);
|
||||
|
||||
template Handle<GlobalDictionary>
|
||||
Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name> >::Add(
|
||||
Handle<GlobalDictionary>, Handle<Name>, Handle<Object>,
|
||||
PropertyDetails);
|
||||
Dictionary<GlobalDictionary, GlobalDictionaryShape, Handle<Name>>::Add(
|
||||
Handle<GlobalDictionary>, Handle<Name>, Handle<Object>, PropertyDetails,
|
||||
int*);
|
||||
|
||||
template Handle<FixedArray> Dictionary<
|
||||
NameDictionary, NameDictionaryShape,
|
||||
@ -16525,18 +16474,14 @@ template Handle<FixedArray> Dictionary<
|
||||
Handle<Name> >::GenerateNewEnumerationIndices(Handle<NameDictionary>);
|
||||
|
||||
template Handle<SeededNumberDictionary>
|
||||
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
|
||||
Add(Handle<SeededNumberDictionary>,
|
||||
uint32_t,
|
||||
Handle<Object>,
|
||||
PropertyDetails);
|
||||
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::Add(
|
||||
Handle<SeededNumberDictionary>, uint32_t, Handle<Object>, PropertyDetails,
|
||||
int*);
|
||||
|
||||
template Handle<UnseededNumberDictionary>
|
||||
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape, uint32_t>::
|
||||
Add(Handle<UnseededNumberDictionary>,
|
||||
uint32_t,
|
||||
Handle<Object>,
|
||||
PropertyDetails);
|
||||
Dictionary<UnseededNumberDictionary, UnseededNumberDictionaryShape,
|
||||
uint32_t>::Add(Handle<UnseededNumberDictionary>, uint32_t,
|
||||
Handle<Object>, PropertyDetails, int*);
|
||||
|
||||
template Handle<SeededNumberDictionary>
|
||||
Dictionary<SeededNumberDictionary, SeededNumberDictionaryShape, uint32_t>::
|
||||
@ -16859,29 +16804,35 @@ void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
|
||||
PropertyCell::InvalidateEntry(dictionary, entry);
|
||||
}
|
||||
|
||||
|
||||
// TODO(ishell): rename to EnsureEmptyPropertyCell or something.
|
||||
Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
|
||||
Handle<JSGlobalObject> global, Handle<Name> name) {
|
||||
Handle<PropertyCell> JSGlobalObject::EnsureEmptyPropertyCell(
|
||||
Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
PropertyCellType cell_type, int* entry_out) {
|
||||
Isolate* isolate = global->GetIsolate();
|
||||
DCHECK(!global->HasFastProperties());
|
||||
auto dictionary = handle(global->global_dictionary(), isolate);
|
||||
Handle<GlobalDictionary> dictionary(global->global_dictionary(), isolate);
|
||||
int entry = dictionary->FindEntry(name);
|
||||
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)));
|
||||
DCHECK(cell->property_details().cell_type() ==
|
||||
PropertyCellType::kUninitialized ||
|
||||
cell->property_details().cell_type() ==
|
||||
PropertyCellType::kInvalidated);
|
||||
PropertyCellType original_cell_type = cell->property_details().cell_type();
|
||||
DCHECK(original_cell_type == PropertyCellType::kInvalidated ||
|
||||
original_cell_type == PropertyCellType::kUninitialized);
|
||||
DCHECK(cell->value()->IsTheHole(isolate));
|
||||
if (original_cell_type == PropertyCellType::kInvalidated) {
|
||||
cell = PropertyCell::InvalidateEntry(dictionary, entry);
|
||||
}
|
||||
PropertyDetails details(NONE, DATA, 0, cell_type);
|
||||
cell->set_property_details(details);
|
||||
return cell;
|
||||
}
|
||||
cell = isolate->factory()->NewPropertyCell();
|
||||
PropertyDetails details(NONE, DATA, 0, PropertyCellType::kUninitialized);
|
||||
dictionary = GlobalDictionary::Add(dictionary, name, cell, details);
|
||||
PropertyDetails details(NONE, DATA, 0, cell_type);
|
||||
dictionary =
|
||||
GlobalDictionary::Add(dictionary, name, cell, details, entry_out);
|
||||
// {*entry_out} is initialized inside GlobalDictionary::Add().
|
||||
global->set_properties(*dictionary);
|
||||
return cell;
|
||||
}
|
||||
@ -17380,31 +17331,28 @@ Handle<Derived> Dictionary<Derived, Shape, Key>::AtPut(
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
|
||||
template<typename Derived, typename Shape, typename Key>
|
||||
Handle<Derived> Dictionary<Derived, Shape, Key>::Add(
|
||||
Handle<Derived> dictionary,
|
||||
Key key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details) {
|
||||
template <typename Derived, typename Shape, typename Key>
|
||||
Handle<Derived> Dictionary<Derived, Shape, Key>::Add(Handle<Derived> dictionary,
|
||||
Key key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details,
|
||||
int* entry_out) {
|
||||
// Valdate key is absent.
|
||||
SLOW_DCHECK((dictionary->FindEntry(key) == Dictionary::kNotFound));
|
||||
// Check whether the dictionary should be extended.
|
||||
dictionary = EnsureCapacity(dictionary, 1, key);
|
||||
|
||||
AddEntry(dictionary, key, value, details, dictionary->Hash(key));
|
||||
int entry = AddEntry(dictionary, key, value, details, dictionary->Hash(key));
|
||||
if (entry_out) *entry_out = entry;
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
|
||||
// Add a key, value pair to the dictionary.
|
||||
template<typename Derived, typename Shape, typename Key>
|
||||
void Dictionary<Derived, Shape, Key>::AddEntry(
|
||||
Handle<Derived> dictionary,
|
||||
Key key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details,
|
||||
uint32_t hash) {
|
||||
// Add a key, value pair to the dictionary. Returns entry value.
|
||||
template <typename Derived, typename Shape, typename Key>
|
||||
int Dictionary<Derived, Shape, Key>::AddEntry(Handle<Derived> dictionary,
|
||||
Key key, Handle<Object> value,
|
||||
PropertyDetails details,
|
||||
uint32_t hash) {
|
||||
// Compute the key object.
|
||||
Handle<Object> k = Shape::AsHandle(dictionary->GetIsolate(), key);
|
||||
|
||||
@ -17421,6 +17369,7 @@ void Dictionary<Derived, Shape, Key>::AddEntry(
|
||||
DCHECK((dictionary->KeyAt(entry)->IsNumber() ||
|
||||
dictionary->KeyAt(entry)->IsName()));
|
||||
dictionary->ElementAdded();
|
||||
return entry;
|
||||
}
|
||||
|
||||
bool SeededNumberDictionary::HasComplexElements() {
|
||||
@ -18811,13 +18760,13 @@ Handle<PropertyCell> PropertyCell::InvalidateEntry(
|
||||
// Swap with a copy.
|
||||
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
|
||||
Handle<PropertyCell> cell(PropertyCell::cast(dictionary->ValueAt(entry)));
|
||||
auto new_cell = isolate->factory()->NewPropertyCell();
|
||||
Handle<PropertyCell> new_cell = isolate->factory()->NewPropertyCell();
|
||||
new_cell->set_value(cell->value());
|
||||
dictionary->ValueAtPut(entry, *new_cell);
|
||||
bool is_the_hole = cell->value()->IsTheHole(isolate);
|
||||
// Cell is officially mutable henceforth.
|
||||
PropertyDetails details = cell->property_details();
|
||||
details = details.set_cell_type(is_the_hole ? PropertyCellType::kInvalidated
|
||||
details = details.set_cell_type(is_the_hole ? PropertyCellType::kUninitialized
|
||||
: PropertyCellType::kMutable);
|
||||
new_cell->set_property_details(details);
|
||||
// Old cell is ready for invalidation.
|
||||
@ -18891,9 +18840,9 @@ PropertyCellType PropertyCell::UpdatedType(Handle<PropertyCell> cell,
|
||||
return PropertyCellType::kMutable;
|
||||
}
|
||||
|
||||
|
||||
void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
|
||||
Handle<Object> value, PropertyDetails details) {
|
||||
Handle<PropertyCell> PropertyCell::PrepareForValue(
|
||||
Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
|
||||
PropertyDetails details) {
|
||||
Isolate* isolate = dictionary->GetIsolate();
|
||||
DCHECK(!value->IsTheHole(isolate));
|
||||
DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
|
||||
@ -18909,8 +18858,6 @@ void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
|
||||
if (cell->value()->IsTheHole(isolate)) {
|
||||
index = dictionary->NextEnumerationIndex();
|
||||
dictionary->SetNextEnumerationIndex(index + 1);
|
||||
// Negative lookup cells must be invalidated.
|
||||
invalidate = true;
|
||||
}
|
||||
DCHECK(index > 0);
|
||||
details = details.set_index(index);
|
||||
@ -18918,10 +18865,9 @@ void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
|
||||
PropertyCellType new_type = UpdatedType(cell, value, original_details);
|
||||
if (invalidate) cell = PropertyCell::InvalidateEntry(dictionary, entry);
|
||||
|
||||
// Install new property details and cell value.
|
||||
// Install new property details.
|
||||
details = details.set_cell_type(new_type);
|
||||
cell->set_property_details(details);
|
||||
cell->set_value(*value);
|
||||
|
||||
// Deopt when transitioning from a constant type.
|
||||
if (!invalidate && (old_type != new_type ||
|
||||
@ -18929,6 +18875,7 @@ void PropertyCell::UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
|
||||
cell->dependent_code()->DeoptimizeDependentCodeGroup(
|
||||
isolate, DependentCode::kPropertyCellChangedGroup);
|
||||
}
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2483,12 +2483,6 @@ class JSObject: public JSReceiver {
|
||||
MUST_USE_RESULT static Maybe<bool> SetPropertyWithFailedAccessCheck(
|
||||
LookupIterator* it, Handle<Object> value, ShouldThrow should_throw);
|
||||
|
||||
// Add a property to a slow-case object.
|
||||
static void AddSlowProperty(Handle<JSObject> object,
|
||||
Handle<Name> name,
|
||||
Handle<Object> value,
|
||||
PropertyAttributes attributes);
|
||||
|
||||
MUST_USE_RESULT static Maybe<bool> DeletePropertyWithInterceptor(
|
||||
LookupIterator* it, ShouldThrow should_throw);
|
||||
|
||||
@ -3518,11 +3512,10 @@ class Dictionary: public HashTable<Derived, Shape, Key> {
|
||||
Handle<Object> value,
|
||||
PropertyDetails details);
|
||||
|
||||
MUST_USE_RESULT static Handle<Derived> Add(
|
||||
Handle<Derived> dictionary,
|
||||
Key key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details);
|
||||
MUST_USE_RESULT static Handle<Derived> Add(Handle<Derived> dictionary,
|
||||
Key key, Handle<Object> value,
|
||||
PropertyDetails details,
|
||||
int* entry_out = nullptr);
|
||||
|
||||
// Returns iteration indices array for the |dictionary|.
|
||||
// Values are direct indices in the |HashTable| array.
|
||||
@ -3536,13 +3529,9 @@ class Dictionary: public HashTable<Derived, Shape, Key> {
|
||||
Key key,
|
||||
Handle<Object> value);
|
||||
|
||||
// Add entry to dictionary.
|
||||
static void AddEntry(
|
||||
Handle<Derived> dictionary,
|
||||
Key key,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details,
|
||||
uint32_t hash);
|
||||
// Add entry to dictionary. Returns entry value.
|
||||
static int AddEntry(Handle<Derived> dictionary, Key key, Handle<Object> value,
|
||||
PropertyDetails details, uint32_t hash);
|
||||
|
||||
// Generate new enumeration indices to avoid enumeration index overflow.
|
||||
// Returns iteration indices array for the |dictionary|.
|
||||
@ -7870,8 +7859,9 @@ class JSGlobalObject : public JSObject {
|
||||
static void InvalidatePropertyCell(Handle<JSGlobalObject> object,
|
||||
Handle<Name> name);
|
||||
// Ensure that the global object has a cell for the given property name.
|
||||
static Handle<PropertyCell> EnsurePropertyCell(Handle<JSGlobalObject> global,
|
||||
Handle<Name> name);
|
||||
static Handle<PropertyCell> EnsureEmptyPropertyCell(
|
||||
Handle<JSGlobalObject> global, Handle<Name> name,
|
||||
PropertyCellType cell_type, int* entry_out = nullptr);
|
||||
|
||||
DECLARE_CAST(JSGlobalObject)
|
||||
|
||||
@ -9721,8 +9711,12 @@ class PropertyCell : public HeapObject {
|
||||
static PropertyCellType UpdatedType(Handle<PropertyCell> cell,
|
||||
Handle<Object> value,
|
||||
PropertyDetails details);
|
||||
static void UpdateCell(Handle<GlobalDictionary> dictionary, int entry,
|
||||
Handle<Object> value, PropertyDetails details);
|
||||
// Prepares property cell at given entry for receiving given value.
|
||||
// As a result the old cell could be invalidated and/or dependent code could
|
||||
// be deoptimized. Returns the prepared property cell.
|
||||
static Handle<PropertyCell> PrepareForValue(
|
||||
Handle<GlobalDictionary> dictionary, int entry, Handle<Object> value,
|
||||
PropertyDetails details);
|
||||
|
||||
static Handle<PropertyCell> InvalidateEntry(
|
||||
Handle<GlobalDictionary> dictionary, int entry);
|
||||
|
@ -209,7 +209,6 @@ static const int kMaxNumberOfDescriptors =
|
||||
static const int kInvalidEnumCacheSentinel =
|
||||
(1 << kDescriptorIndexBitCount) - 1;
|
||||
|
||||
|
||||
enum class PropertyCellType {
|
||||
// Meaningful when a property cell does not contain the hole.
|
||||
kUndefined, // The PREMONOMORPHIC of property cells.
|
||||
@ -219,13 +218,13 @@ enum class PropertyCellType {
|
||||
|
||||
// Meaningful when a property cell contains the hole.
|
||||
kUninitialized = kUndefined, // Cell has never been initialized.
|
||||
kInvalidated = kConstant, // Cell has been deleted or invalidated.
|
||||
kInvalidated = kConstant, // Cell has been deleted, invalidated or never
|
||||
// existed.
|
||||
|
||||
// For dictionaries not holding cells.
|
||||
kNoCell = kMutable,
|
||||
};
|
||||
|
||||
|
||||
enum class PropertyCellConstantType {
|
||||
kSmi,
|
||||
kStableMap,
|
||||
@ -265,8 +264,9 @@ class PropertyDetails BASE_EMBEDDED {
|
||||
FieldIndexField::encode(field_index);
|
||||
}
|
||||
|
||||
static PropertyDetails Empty() {
|
||||
return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
|
||||
static PropertyDetails Empty(
|
||||
PropertyCellType cell_type = PropertyCellType::kNoCell) {
|
||||
return PropertyDetails(NONE, DATA, 0, cell_type);
|
||||
}
|
||||
|
||||
int pointer() const { return DescriptorPointer::decode(value_); }
|
||||
|
Loading…
Reference in New Issue
Block a user