Commit c22bb466 authored by Matt Gardner's avatar Matt Gardner Committed by Commit Bot

Inline indexOf/includes at polymorphic sites

This commit allows inlining of Array#indexOf and Array#includes when the array type is polymorphic for types that are compatable for array iteration.

Bug: v8:8388
Change-Id: Ib826bad857c7dfe0ee7af99bb456b50b7a8b6ef9
Reviewed-on: https://chromium-review.googlesource.com/c/1450137
Commit-Queue: Benedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59473}
parent ead726f3
......@@ -2565,23 +2565,29 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
return NoChange();
}
Handle<Map> map;
if (!NodeProperties::GetMapWitness(broker(), node).ToHandle(&map))
return NoChange();
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
MapRef receiver_map(broker(), map);
if (!receiver_map.supports_fast_array_iteration()) return NoChange();
ZoneHandleSet<Map> receiver_maps;
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(broker(), receiver, effect,
&receiver_maps);
if (result == NodeProperties::kNoReceiverMaps) return NoChange();
ElementsKind const elements_kind = receiver_map.elements_kind();
if (IsHoleyElementsKind(elements_kind)) {
ElementsKind kind;
if (!CanInlineArrayIteratingBuiltin(broker(), receiver_maps, &kind)) {
return NoChange();
}
if (IsHoleyElementsKind(kind)) {
dependencies()->DependOnProtector(
PropertyCellRef(broker(), factory()->no_elements_protector()));
}
Callable const callable =
search_variant == SearchVariant::kIndexOf
? GetCallableForArrayIndexOf(elements_kind, isolate())
: GetCallableForArrayIncludes(elements_kind, isolate());
Callable const callable = search_variant == SearchVariant::kIndexOf
? GetCallableForArrayIndexOf(kind, isolate())
: GetCallableForArrayIncludes(kind, isolate());
CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(),
callable.descriptor().GetStackParameterCount(), CallDescriptor::kNoFlags,
......@@ -2589,9 +2595,6 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
// The stub expects the following arguments: the receiver array, its elements,
// the search_element, the array length, and the index to start searching
// from.
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* elements = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
effect, control);
......@@ -2599,8 +2602,8 @@ Reduction JSCallReducer::ReduceArrayIndexOfIncludes(
? NodeProperties::GetValueInput(node, 2)
: jsgraph()->UndefinedConstant();
Node* length = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForJSArrayLength(elements_kind)),
receiver, effect, control);
simplified()->LoadField(AccessBuilder::ForJSArrayLength(kind)), receiver,
effect, control);
Node* new_from_index = jsgraph()->ZeroConstant();
if (node->op()->ValueInputCount() >= 4) {
Node* from_index = NodeProperties::GetValueInput(node, 3);
......
......@@ -13,7 +13,6 @@
#include "src/compiler/verifier.h"
#include "src/handles-inl.h"
#include "src/objects-inl.h"
#include "src/zone/zone-handle-set.h"
namespace v8 {
namespace internal {
......@@ -510,20 +509,6 @@ NodeProperties::InferReceiverMapsResult NodeProperties::InferReceiverMaps(
}
}
// static
MaybeHandle<Map> NodeProperties::GetMapWitness(JSHeapBroker* broker,
Node* node) {
ZoneHandleSet<Map> maps;
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* effect = NodeProperties::GetEffectInput(node);
NodeProperties::InferReceiverMapsResult result =
NodeProperties::InferReceiverMaps(broker, receiver, effect, &maps);
if (result == NodeProperties::kReliableReceiverMaps && maps.size() == 1) {
return maps[0];
}
return MaybeHandle<Map>();
}
// static
bool NodeProperties::HasInstanceTypeWitness(JSHeapBroker* broker,
Node* receiver, Node* effect,
......
......@@ -155,7 +155,6 @@ class V8_EXPORT_PRIVATE NodeProperties final {
JSHeapBroker* broker, Node* receiver, Node* effect,
ZoneHandleSet<Map>* maps_return);
static MaybeHandle<Map> GetMapWitness(JSHeapBroker* broker, Node* node);
static bool HasInstanceTypeWitness(JSHeapBroker* broker, Node* receiver,
Node* effect, InstanceType instance_type);
......
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax
var o1 = {};
var o2 = {};
var a = [0, 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,0,0];
var b = [,,,,,2,3,4];
var c = [o1, o2];
var d = [,,, o2, o1];
var e = [0.5,3,4];
var f = [,,,,0.5,3,4];
function checkIncludes(ary, value) {
return ary.includes(value)
}
function checkIndexOf(ary, value, expected) {
return ary.indexOf(value) == expected;
}
function expectIncludes(ary, value) {
assertTrue(checkIncludes(ary, value));
}
function expectNotIncludes(ary, value) {
assertFalse(checkIncludes(ary, value));
}
function expectIndexOf(ary, value, expected) {
assertTrue(checkIndexOf(ary, value, expected));
}
var testIncludes = {
polymorphic: function() {
expectIncludes(a, 21);
expectIncludes(b, 4);
expectIncludes(c, o2);
expectIncludes(d, o1);
expectNotIncludes(a, o1);
expectNotIncludes(b, o2);
expectNotIncludes(c, 3);
expectNotIncludes(d, 4);
},
polymorphicDouble: function() {
expectIncludes(e, 3);
expectIncludes(f, 0.5);
expectNotIncludes(e, 10);
expectNotIncludes(f, 0.25);
},
polymorphicMixed: function() {
expectIncludes(a, 21);
expectIncludes(b, 4);
expectIncludes(c, o2);
expectIncludes(d, o1);
expectIncludes(e, 3);
expectIncludes(f, 0.5);
expectNotIncludes(a, o1);
expectNotIncludes(b, o2);
expectNotIncludes(c, 3);
expectNotIncludes(d, 4);
expectNotIncludes(e, 10);
expectNotIncludes(f, 0.25);
},
};
var testIndexOf = {
polymorphic: function() {
expectIndexOf(a, 21, 21);
expectIndexOf(b, 4, 7);
expectIndexOf(c, o2, 1);
expectIndexOf(d, o1, 4);
expectIndexOf(a, o1, -1);
expectIndexOf(b, o2, -1);
expectIndexOf(c, 3, -1);
expectIndexOf(d, 4, -1);
},
polymorphicDouble: function() {
expectIndexOf(e, 3, 1);
expectIndexOf(f, 0.5, 4);
expectIndexOf(e, 10, -1);
expectIndexOf(f, 0.25, -1);
},
polymorphicMixed: function() {
expectIndexOf(a, 21, 21);
expectIndexOf(b, 4, 7);
expectIndexOf(c, o2, 1);
expectIndexOf(d, o1, 4);
expectIndexOf(e, 3, 1);
expectIndexOf(f, 0.5, 4);
expectIndexOf(a, o1, -1);
expectIndexOf(b, o2, -1);
expectIndexOf(c, 3, -1);
expectIndexOf(d, 4, -1);
expectIndexOf(e, 10, -1);
expectIndexOf(f, 0.25, -1);
},
};
function runTests(tests, func) {
for (test in tests) {
%DeoptimizeFunction(func);
%ClearFunctionFeedback(func);
tests[test]();
%OptimizeFunctionOnNextCall(func);
tests[test]();
}
}
runTests(testIncludes, checkIncludes)
runTests(testIndexOf, checkIndexOf)
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