[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:
ishell 2016-07-07 05:32:15 -07:00 committed by Commit bot
parent 07612e0d35
commit 3fbb45216d
16 changed files with 238 additions and 186 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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