Index: src/compiler/js-native-context-specialization.cc |
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc |
index 602446f651622fc4aa7d071d7feea2b7f51740d9..842b002da7d68dca87c3df8f8f762ec214c5cc09 100644 |
--- a/src/compiler/js-native-context-specialization.cc |
+++ b/src/compiler/js-native-context-specialization.cc |
@@ -1623,19 +1623,42 @@ JSNativeContextSpecialization::BuildPropertyAccess( |
UNREACHABLE(); |
break; |
} |
+ // Check if we need to perform a transitioning store. |
Handle<Map> transition_map; |
if (access_info.transition_map().ToHandle(&transition_map)) { |
+ // Check if we need to grow the properties backing store |
+ // with this transitioning store. |
+ Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()), |
+ isolate()); |
+ if (original_map->unused_property_fields() == 0) { |
+ DCHECK(!field_index.is_inobject()); |
+ |
+ // Reallocate the properties {storage}. |
+ storage = effect = BuildExtendPropertiesBackingStore( |
+ original_map, storage, effect, control); |
+ |
+ // Perform the actual store. |
+ effect = graph()->NewNode(simplified()->StoreField(field_access), |
+ storage, value, effect, control); |
+ |
+ // Atomically switch to the new properties below. |
+ field_access = AccessBuilder::ForJSObjectProperties(); |
+ value = storage; |
+ storage = receiver; |
+ } |
effect = graph()->NewNode( |
common()->BeginRegion(RegionObservability::kObservable), effect); |
effect = graph()->NewNode( |
simplified()->StoreField(AccessBuilder::ForMap()), receiver, |
jsgraph()->Constant(transition_map), effect, control); |
- } |
- effect = graph()->NewNode(simplified()->StoreField(field_access), storage, |
- value, effect, control); |
- if (access_info.HasTransitionMap()) { |
+ effect = graph()->NewNode(simplified()->StoreField(field_access), |
+ storage, value, effect, control); |
effect = graph()->NewNode(common()->FinishRegion(), |
jsgraph()->UndefinedConstant(), effect); |
+ } else { |
+ // Regular non-transitioning field store. |
+ effect = graph()->NewNode(simplified()->StoreField(field_access), |
+ storage, value, effect, control); |
} |
} |
} else { |
@@ -2163,6 +2186,45 @@ Node* JSNativeContextSpecialization::BuildCheckMaps( |
effect, control); |
} |
+Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( |
+ Handle<Map> map, Node* properties, Node* effect, Node* control) { |
+ DCHECK_EQ(0, map->unused_property_fields()); |
+ // Compute the length of the old {properties} and the new properties. |
+ int length = map->NextFreePropertyIndex() - map->GetInObjectProperties(); |
+ int new_length = length + JSObject::kFieldsAdded; |
+ // Collect the field values from the {properties}. |
+ ZoneVector<Node*> values(zone()); |
+ values.reserve(new_length); |
+ for (int i = 0; i < length; ++i) { |
+ Node* value = effect = graph()->NewNode( |
+ simplified()->LoadField(AccessBuilder::ForFixedArraySlot(i)), |
+ properties, effect, control); |
+ values.push_back(value); |
+ } |
+ // Initialize the new fields to undefined. |
+ for (int i = 0; i < JSObject::kFieldsAdded; ++i) { |
+ values.push_back(jsgraph()->UndefinedConstant()); |
+ } |
+ // Allocate and initialize the new properties. |
+ effect = graph()->NewNode( |
+ common()->BeginRegion(RegionObservability::kNotObservable), effect); |
+ Node* new_properties = effect = graph()->NewNode( |
+ simplified()->Allocate(Type::OtherInternal(), NOT_TENURED), |
+ jsgraph()->Constant(FixedArray::SizeFor(new_length)), effect, control); |
+ effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()), |
+ new_properties, jsgraph()->FixedArrayMapConstant(), |
+ effect, control); |
+ effect = graph()->NewNode( |
+ simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), |
+ new_properties, jsgraph()->Constant(new_length), effect, control); |
+ for (int i = 0; i < new_length; ++i) { |
+ effect = graph()->NewNode( |
+ simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), |
+ new_properties, values[i], effect, control); |
+ } |
+ return graph()->NewNode(common()->FinishRegion(), new_properties, effect); |
+} |
+ |
void JSNativeContextSpecialization::AssumePrototypesStable( |
std::vector<Handle<Map>> const& receiver_maps, Handle<JSObject> holder) { |
// Determine actual holder and perform prototype chain checks. |