[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: Benedikt Meurer <bmeurer@chromium.org> Cr-Commit-Position: refs/heads/master@{#50284}
This commit is contained in:
parent
7bcd92650c
commit
dcd60e8c55
@ -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);
|
||||
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(receiver_map, 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(receiver_map, node,
|
||||
IterationKind::kEntries);
|
||||
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(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(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(receiver_map, node,
|
||||
IterationKind::kValues);
|
||||
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(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(type, node, IterationKind::kValues);
|
||||
|
||||
default:
|
||||
// Slow array iterators are not reduced
|
||||
return NoChange();
|
||||
}
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user