Commit f6d1dc40 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

Support holey elements kind (not double) in TF-inlined forEach

BUG=v8:1956
LOG=N
R=bmeurer@chromium.org

Change-Id: I190002227d3321df0f68e77f3b7b0a468446c493
Reviewed-on: https://chromium-review.googlesource.com/561011
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46513}
parent f0146761
......@@ -488,6 +488,18 @@ Reduction JSCallReducer::ReduceReflectGetPrototypeOf(Node* node) {
return ReduceObjectGetPrototype(node, target);
}
bool CanInlineArrayIteratingBuiltin(Handle<Map> receiver_map) {
Isolate* const isolate = receiver_map->GetIsolate();
if (!receiver_map->prototype()->IsJSArray()) return false;
Handle<JSArray> receiver_prototype(JSArray::cast(receiver_map->prototype()),
isolate);
return receiver_map->instance_type() == JS_ARRAY_TYPE &&
IsFastElementsKind(receiver_map->elements_kind()) &&
(!receiver_map->is_prototype_map() || receiver_map->is_stable()) &&
isolate->IsFastArrayConstructorPrototypeChainIntact() &&
isolate->IsAnyInitialArrayPrototype(receiver_prototype);
}
Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
Node* node) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
......@@ -515,15 +527,20 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
if (receiver_maps.size() != 1) return NoChange();
Handle<Map> receiver_map(receiver_maps[0]);
ElementsKind kind = receiver_map->elements_kind();
// TODO(danno): Handle holey Smi and Object fast elements kinds and double
// packed.
if (!IsFastPackedElementsKind(kind) || IsDoubleElementsKind(kind)) {
// TODO(danno): Handle double packed elements
if (!IsFastElementsKind(kind) || IsDoubleElementsKind(kind) ||
!CanInlineArrayIteratingBuiltin(receiver_map)) {
return NoChange();
}
// TODO(danno): forEach can throw. Hook up exceptional edges.
if (NodeProperties::IsExceptionalCall(node)) return NoChange();
// Install code dependencies on the {receiver} prototype maps and the
// global array protector cell.
dependencies()->AssumePropertyCell(factory()->array_protector());
dependencies()->AssumePrototypeMapsStable(receiver_map);
Node* k = jsgraph()->ZeroConstant();
Node* original_length = graph()->NewNode(
......@@ -592,6 +609,23 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
Node* next_k =
graph()->NewNode(simplified()->NumberAdd(), k, jsgraph()->Constant(1));
checkpoint_params[3] = next_k;
Node* hole_true = nullptr;
Node* hole_false = nullptr;
Node* effect_true = effect;
if (IsHoleyElementsKind(kind)) {
// Holey elements kind require a hole check and skipping of the element in
// the case of a hole.
Node* check = graph()->NewNode(simplified()->ReferenceEqual(), element,
jsgraph()->TheHoleConstant());
Node* branch =
graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);
hole_true = graph()->NewNode(common()->IfTrue(), branch);
hole_false = graph()->NewNode(common()->IfFalse(), branch);
control = hole_false;
}
frame_state = CreateJavaScriptBuiltinContinuationFrameState(
jsgraph(), function, Builtins::kArrayForEachLoopLazyDeoptContinuation,
node->InputAt(0), context, &checkpoint_params[0], stack_parameters,
......@@ -601,6 +635,17 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
receiver, context, frame_state, effect, control);
if (IsHoleyElementsKind(kind)) {
Node* after_call_control = control;
Node* after_call_effect = effect;
control = hole_true;
effect = effect_true;
control = graph()->NewNode(common()->Merge(2), control, after_call_control);
effect = graph()->NewNode(common()->EffectPhi(2), effect, after_call_effect,
control);
}
k = next_k;
loop->ReplaceInput(1, control);
......
// Copyright 2017 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 --expose-gc --turbo-inline-array-builtins
(function() {
var result = 0;
var proto_set_func = function(p, s) {
%NeverOptimizeFunction(proto_set_func);
if (s) {
p[0] = 1;
}
}
var f = function(s) {
var b = [,,];
proto_set_func(b.__proto__, s);
b[1] = 0;
b[2] = 2;
var sum = function(v,i,o) {
result += v;
};
b.forEach(sum);
}
f();
f();
%OptimizeFunctionOnNextCall(f);
f();
f(true);
f();
assertEquals(12, result);
})();
// Copyright 2017 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 --expose-gc --turbo-inline-array-builtins
(function() {
var result = 0;
var proto_set_func = function(p, s) {
%NeverOptimizeFunction(proto_set_func);
if (s) {
p[0] = 1;
}
}
var f = function(s) {
var b = [,,];
b[1] = 0;
b[2] = 2;
var sum = function(v,i,o) {
if (i==1) proto_set_func(b.__proto__, s);
result += v;
};
b.forEach(sum);
}
f();
f();
%OptimizeFunctionOnNextCall(f);
f();
f(true);
f();
assertEquals(11, result);
})();
// Copyright 2017 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 --expose-gc --turbo-inline-array-builtins
(function() {
var result = 0;
var f = function() {
var b = [,,];
b[0] = 0;
b[2] = 2;
var sum = function(v,i,o) {
result += i;
};
b.forEach(sum);
}
f();
f();
%OptimizeFunctionOnNextCall(f);
f();
f();
f();
assertEquals(10, result);
})();
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