summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/map-updater.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/objects/map-updater.cc')
-rw-r--r--deps/v8/src/objects/map-updater.cc55
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;