Commit dcd60e8c authored by Caitlin Potter's avatar Caitlin Potter Committed by Commit Bot

[turbofan] Reduce ArrayIteratorNext based on instance type

NodeProperties::InferReceiverMaps now traverses effect chain for
Loop-EffectPhi nodes, which makes it possible to inline `iterator.next()`
within a loop when the next property is loaded outside of a loop.

A new helper, GetInstanceTypeWitness(), performs InferReceiverMaps() and
checks that each resulting map has an identical instance type.

BUG=chromium:795632, v8:5940, v8:3018
R=bmeurer@chromium.org, jarin@chromium.org

Change-Id: Id2690c224668bea62dbcad62ebc2bdf7e37e80d3
Reviewed-on: https://chromium-review.googlesource.com/837484
Commit-Queue: Caitlin Potter <caitp@igalia.com>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50284}
parent 7bcd9265
...@@ -121,6 +121,24 @@ MaybeHandle<Map> GetMapWitness(Node* node) { ...@@ -121,6 +121,24 @@ MaybeHandle<Map> GetMapWitness(Node* node) {
return MaybeHandle<Map>(); return MaybeHandle<Map>();
} }
Maybe<InstanceType> GetInstanceTypeWitness(Node* node) {
ZoneHandleSet<Map> maps;
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(receiver, effect, &maps);
if (result == NodeProperties::kNoReceiverMaps || maps.size() == 0) {
return Nothing<InstanceType>();
}
InstanceType first_type = maps[0]->instance_type();
for (const Handle<Map>& map : maps) {
if (map->instance_type() != first_type) return Nothing<InstanceType>();
}
return Just(first_type);
}
// TODO(turbofan): This was copied from Crankshaft, might be too restrictive. // TODO(turbofan): This was copied from Crankshaft, might be too restrictive.
bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) { bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
DCHECK(!jsarray_map->is_dictionary_map()); DCHECK(!jsarray_map->is_dictionary_map());
...@@ -313,8 +331,9 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map, ...@@ -313,8 +331,9 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
return Replace(value); return Replace(value);
} }
Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext( Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(InstanceType type,
Handle<Map> iterator_map, Node* node, IterationKind kind) { Node* node,
IterationKind kind) {
Node* iterator = NodeProperties::GetValueInput(node, 1); Node* iterator = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
...@@ -327,8 +346,8 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext( ...@@ -327,8 +346,8 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
return NoChange(); return NoChange();
} }
ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType( ElementsKind elements_kind =
iterator_map->instance_type()); JSArrayIterator::ElementsKindForInstanceType(type);
if (IsHoleyElementsKind(elements_kind)) { if (IsHoleyElementsKind(elements_kind)) {
if (!isolate()->IsNoElementsProtectorIntact()) { if (!isolate()->IsNoElementsProtectorIntact()) {
...@@ -484,15 +503,16 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext( ...@@ -484,15 +503,16 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
return Replace(value); return Replace(value);
} }
Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext( Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(InstanceType type,
Handle<Map> iterator_map, Node* node, IterationKind kind) { Node* node,
IterationKind kind) {
Node* iterator = NodeProperties::GetValueInput(node, 1); Node* iterator = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node); Node* context = NodeProperties::GetContextInput(node);
ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType( ElementsKind elements_kind =
iterator_map->instance_type()); JSArrayIterator::ElementsKindForInstanceType(type);
Node* array = effect = graph()->NewNode( Node* array = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()), simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
...@@ -725,16 +745,15 @@ Reduction JSBuiltinReducer::ReduceTypedArrayToStringTag(Node* node) { ...@@ -725,16 +745,15 @@ Reduction JSBuiltinReducer::ReduceTypedArrayToStringTag(Node* node) {
} }
Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) { Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
Handle<Map> receiver_map; Maybe<InstanceType> maybe_type = GetInstanceTypeWitness(node);
if (GetMapWitness(node).ToHandle(&receiver_map)) { if (!maybe_type.IsJust()) return NoChange();
switch (receiver_map->instance_type()) { InstanceType type = maybe_type.FromJust();
switch (type) {
case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE: case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(receiver_map, node, return ReduceTypedArrayIteratorNext(type, node, IterationKind::kKeys);
IterationKind::kKeys);
case JS_FAST_ARRAY_KEY_ITERATOR_TYPE: case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(receiver_map, node, return ReduceFastArrayIteratorNext(type, node, IterationKind::kKeys);
IterationKind::kKeys);
case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
...@@ -745,8 +764,7 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) { ...@@ -745,8 +764,7 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(receiver_map, node, return ReduceTypedArrayIteratorNext(type, node, IterationKind::kEntries);
IterationKind::kEntries);
case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
...@@ -754,8 +772,7 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) { ...@@ -754,8 +772,7 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(receiver_map, node, return ReduceFastArrayIteratorNext(type, node, IterationKind::kEntries);
IterationKind::kEntries);
case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE: case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE: case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
...@@ -766,8 +783,7 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) { ...@@ -766,8 +783,7 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE: case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE: case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE: case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(receiver_map, node, return ReduceTypedArrayIteratorNext(type, node, IterationKind::kValues);
IterationKind::kValues);
case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE: case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE: case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
...@@ -775,15 +791,12 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) { ...@@ -775,15 +791,12 @@ Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE: case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(receiver_map, node, return ReduceFastArrayIteratorNext(type, node, IterationKind::kValues);
IterationKind::kValues);
default: default:
// Slow array iterators are not reduced // Slow array iterators are not reduced
return NoChange(); return NoChange();
} }
}
return NoChange();
} }
// ES6 section 22.1.2.2 Array.isArray ( arg ) // ES6 section 22.1.2.2 Array.isArray ( arg )
......
...@@ -47,9 +47,9 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final ...@@ -47,9 +47,9 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
IterationKind kind, IterationKind kind,
ArrayIteratorKind iter_kind); ArrayIteratorKind iter_kind);
Reduction ReduceArrayIteratorNext(Node* node); Reduction ReduceArrayIteratorNext(Node* node);
Reduction ReduceFastArrayIteratorNext(Handle<Map> iterator_map, Node* node, Reduction ReduceFastArrayIteratorNext(InstanceType type, Node* node,
IterationKind kind); IterationKind kind);
Reduction ReduceTypedArrayIteratorNext(Handle<Map> iterator_map, Node* node, Reduction ReduceTypedArrayIteratorNext(InstanceType type, Node* node,
IterationKind kind); IterationKind kind);
Reduction ReduceTypedArrayToStringTag(Node* node); Reduction ReduceTypedArrayToStringTag(Node* node);
Reduction ReduceArrayIsArray(Node* node); Reduction ReduceArrayIsArray(Node* node);
......
...@@ -461,6 +461,19 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps( ...@@ -461,6 +461,19 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
if (IsSame(receiver, effect)) receiver = GetValueInput(effect, 0); if (IsSame(receiver, effect)) receiver = GetValueInput(effect, 0);
break; break;
} }
case IrOpcode::kEffectPhi: {
Node* control = GetControlInput(effect);
if (control->opcode() != IrOpcode::kLoop) {
DCHECK_EQ(IrOpcode::kMerge, control->opcode());
return kNoReceiverMaps;
}
// Continue search for receiver map outside the loop. Since operations
// inside the loop may change the map, the result is unreliable.
effect = GetEffectInput(effect, 0);
result = kUnreliableReceiverMaps;
continue;
}
default: { default: {
DCHECK_EQ(1, effect->op()->EffectOutputCount()); DCHECK_EQ(1, effect->op()->EffectOutputCount());
if (effect->op()->EffectInputCount() != 1) { if (effect->op()->EffectInputCount() != 1) {
......
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