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) {
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.
bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map) {
DCHECK(!jsarray_map->is_dictionary_map());
......@@ -313,8 +331,9 @@ Reduction JSBuiltinReducer::ReduceArrayIterator(Handle<Map> receiver_map,
return Replace(value);
}
Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
Handle<Map> iterator_map, Node* node, IterationKind kind) {
Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(InstanceType type,
Node* node,
IterationKind kind) {
Node* iterator = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
......@@ -327,8 +346,8 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
return NoChange();
}
ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
iterator_map->instance_type());
ElementsKind elements_kind =
JSArrayIterator::ElementsKindForInstanceType(type);
if (IsHoleyElementsKind(elements_kind)) {
if (!isolate()->IsNoElementsProtectorIntact()) {
......@@ -484,15 +503,16 @@ Reduction JSBuiltinReducer::ReduceFastArrayIteratorNext(
return Replace(value);
}
Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(
Handle<Map> iterator_map, Node* node, IterationKind kind) {
Reduction JSBuiltinReducer::ReduceTypedArrayIteratorNext(InstanceType type,
Node* node,
IterationKind kind) {
Node* iterator = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
ElementsKind elements_kind = JSArrayIterator::ElementsKindForInstanceType(
iterator_map->instance_type());
ElementsKind elements_kind =
JSArrayIterator::ElementsKindForInstanceType(type);
Node* array = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayIteratorObject()),
......@@ -725,65 +745,58 @@ Reduction JSBuiltinReducer::ReduceTypedArrayToStringTag(Node* node) {
}
Reduction JSBuiltinReducer::ReduceArrayIteratorNext(Node* node) {
Handle<Map> receiver_map;
if (GetMapWitness(node).ToHandle(&receiver_map)) {
switch (receiver_map->instance_type()) {
case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(receiver_map, node,
IterationKind::kKeys);
case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(receiver_map, node,
IterationKind::kKeys);
case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(receiver_map, node,
IterationKind::kEntries);
case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_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_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(receiver_map, node,
IterationKind::kEntries);
case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(receiver_map, node,
IterationKind::kValues);
case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(receiver_map, node,
IterationKind::kValues);
default:
// Slow array iterators are not reduced
return NoChange();
}
Maybe<InstanceType> maybe_type = GetInstanceTypeWitness(node);
if (!maybe_type.IsJust()) return NoChange();
InstanceType type = maybe_type.FromJust();
switch (type) {
case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(type, node, IterationKind::kKeys);
case JS_FAST_ARRAY_KEY_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(type, node, IterationKind::kKeys);
case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(type, node, IterationKind::kEntries);
case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE:
case JS_FAST_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_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(type, node, IterationKind::kEntries);
case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE:
case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE:
case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE:
case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE:
return ReduceTypedArrayIteratorNext(type, node, IterationKind::kValues);
case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE:
return ReduceFastArrayIteratorNext(type, node, IterationKind::kValues);
default:
// Slow array iterators are not reduced
return NoChange();
}
return NoChange();
}
// ES6 section 22.1.2.2 Array.isArray ( arg )
......
......@@ -47,9 +47,9 @@ class V8_EXPORT_PRIVATE JSBuiltinReducer final
IterationKind kind,
ArrayIteratorKind iter_kind);
Reduction ReduceArrayIteratorNext(Node* node);
Reduction ReduceFastArrayIteratorNext(Handle<Map> iterator_map, Node* node,
Reduction ReduceFastArrayIteratorNext(InstanceType type, Node* node,
IterationKind kind);
Reduction ReduceTypedArrayIteratorNext(Handle<Map> iterator_map, Node* node,
Reduction ReduceTypedArrayIteratorNext(InstanceType type, Node* node,
IterationKind kind);
Reduction ReduceTypedArrayToStringTag(Node* node);
Reduction ReduceArrayIsArray(Node* node);
......
......@@ -461,6 +461,19 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
if (IsSame(receiver, effect)) receiver = GetValueInput(effect, 0);
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: {
DCHECK_EQ(1, effect->op()->EffectOutputCount());
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