diff options
Diffstat (limited to 'deps/v8/src/objects/map-updater.cc')
-rw-r--r-- | deps/v8/src/objects/map-updater.cc | 55 |
1 files changed, 45 insertions, 10 deletions
diff --git a/deps/v8/src/objects/map-updater.cc b/deps/v8/src/objects/map-updater.cc index 0e0c3372cd..95b435085e 100644 --- a/deps/v8/src/objects/map-updater.cc +++ b/deps/v8/src/objects/map-updater.cc @@ -46,11 +46,15 @@ PropertyDetails MapUpdater::GetDetails(InternalIndex descriptor) const { DCHECK(descriptor.is_found()); if (descriptor == modified_descriptor_) { PropertyAttributes attributes = new_attributes_; - // If the original map was sealed or frozen, let us used the old + // If the original map was sealed or frozen, let's use the old // attributes so that we follow the same transition path as before. // Note that the user could not have changed the attributes because - // both seal and freeze make the properties non-configurable. - if (integrity_level_ == SEALED || integrity_level_ == FROZEN) { + // both seal and freeze make the properties non-configurable. An exception + // is transitioning from [[Writable]] = true to [[Writable]] = false (this + // is allowed for frozen and sealed objects). To support it, we use the new + // attributes if they have [[Writable]] == false. + if ((integrity_level_ == SEALED || integrity_level_ == FROZEN) && + !(new_attributes_ & READ_ONLY)) { attributes = old_descriptors_->GetDetails(descriptor).attributes(); } return PropertyDetails(new_kind_, attributes, new_location_, new_constness_, @@ -121,6 +125,41 @@ Handle<Map> MapUpdater::ReconfigureToDataField(InternalIndex descriptor, PropertyDetails old_details = old_descriptors_->GetDetails(modified_descriptor_); + // If the {descriptor} was "const" data field so far, we need to update the + // {old_map_} here, otherwise we could get the constants wrong, i.e. + // + // o.x = 1; + // change o.x's attributes to something else + // delete o.x; + // o.x = 2; + // + // could trick V8 into thinking that `o.x` is still 1 even after the second + // assignment. + // This situation is similar to what might happen with property deletion. + if (old_details.constness() == PropertyConstness::kConst && + old_details.location() == kField && + old_details.attributes() != new_attributes_) { + Handle<FieldType> field_type( + old_descriptors_->GetFieldType(modified_descriptor_), isolate_); + Map::GeneralizeField(isolate_, old_map_, descriptor, + PropertyConstness::kMutable, + old_details.representation(), field_type); + // The old_map_'s property must become mutable. + // Note, that the {old_map_} and {old_descriptors_} are not expected to be + // updated by the generalization if the map is already deprecated. + DCHECK_IMPLIES( + !old_map_->is_deprecated(), + PropertyConstness::kMutable == + old_descriptors_->GetDetails(modified_descriptor_).constness()); + // Although the property in the old map is marked as mutable we still + // treat it as constant when merging with the new path in transition tree. + // This is fine because up until this reconfiguration the field was + // known to be constant, so it's fair to proceed treating it as such + // during this reconfiguration session. The issue is that after the + // reconfiguration the original field might become mutable (see the delete + // example above). + } + // If property kind is not reconfigured merge the result with // representation/field type from the old descriptor. if (old_details.kind() == new_kind_) { @@ -775,17 +814,13 @@ MapUpdater::State MapUpdater::ConstructNewMap() { old_value, new_field_type, new_value); } - Handle<LayoutDescriptor> new_layout_descriptor = - LayoutDescriptor::New(isolate_, split_map, new_descriptors, old_nof_); - - Handle<Map> new_map = Map::AddMissingTransitions( - isolate_, split_map, new_descriptors, new_layout_descriptor); + Handle<Map> new_map = + Map::AddMissingTransitions(isolate_, split_map, new_descriptors); // Deprecated part of the transition tree is no longer reachable, so replace // current instance descriptors in the "survived" part of the tree with // the new descriptors to maintain descriptors sharing invariant. - split_map->ReplaceDescriptors(isolate_, *new_descriptors, - *new_layout_descriptor); + split_map->ReplaceDescriptors(isolate_, *new_descriptors); if (has_integrity_level_transition_) { target_map_ = new_map; |