Commit 4faa4952 authored by bmeurer's avatar bmeurer Committed by Commit bot

[turbofan] Add support for extending properties backing store.

TurboFan didn't support transitioning stores that also need to grow the
properties backing store so far. This CL adds support for re-allocating
the properties backing store in-place, so these stores can participate
properly in various optimizations like escape analysis and allocation
folding.

R=ishell@chromium.org
BUG=v8:5267,chromium:708339

Review-Url: https://codereview.chromium.org/2778133003
Cr-Original-Commit-Position: refs/heads/master@{#44183}
Committed: https://chromium.googlesource.com/v8/v8/+/88a7061a53ad200121f7ee2b2bdcc05d793de806
Review-Url: https://codereview.chromium.org/2778133003
Cr-Commit-Position: refs/heads/master@{#44499}
parent 0a8c3942
......@@ -515,10 +515,6 @@ bool AccessInfoFactory::LookupTransition(Handle<Map> map, Handle<Name> name,
MaybeHandle<JSObject> holder,
PropertyAccessInfo* access_info) {
// Check if the {map} has a data transition with the given {name}.
if (map->unused_property_fields() == 0) {
*access_info = PropertyAccessInfo::Generic(MapList{map});
return true;
}
Handle<Map> transition_map;
if (TransitionArray::SearchTransition(map, kData, name, NONE)
.ToHandle(&transition_map)) {
......
......@@ -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.
......
......@@ -132,6 +132,10 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
Node* BuildCheckMaps(Node* receiver, Node* effect, Node* control,
std::vector<Handle<Map>> const& maps);
// Construct appropriate subgraph to extend properties backing store.
Node* BuildExtendPropertiesBackingStore(Handle<Map> map, Node* properties,
Node* effect, Node* control);
// Adds stability dependencies on all prototypes of every class in
// {receiver_type} up to (and including) the {holder}.
void AssumePrototypesStable(std::vector<Handle<Map>> const& receiver_maps,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment