Commit 6630a1f1 authored by Sigurd Schneider's avatar Sigurd Schneider Committed by Commit Bot

[turbofan] Disallow speculation after deopt from array builtin

This disallows speculation after deoptimization from any of
Array.{forEach,map,filter,find} due to CheckMap fails. Such
CheckMap fails happen if the builtins' function argument
causes the map of the array to change. The js-call-lowering
refrains from optimizing builtins for which speculation was
disallowed.

Bug: v8:6898, v8:7127
Change-Id: Ied6696f8fb023ee404fb82e9d37bfb061f293854
Reviewed-on: https://chromium-review.googlesource.com/819354Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50069}
parent 4b3043ef
......@@ -795,11 +795,15 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
Node* node) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
CallParameters const& p = CallParametersOf(node->op());
// Try to determine the {receiver} map.
Node* receiver = NodeProperties::GetValueInput(node, 1);
......@@ -893,9 +897,10 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
// Make sure the map hasn't changed during the iteration
effect = graph()->NewNode(
simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
effect, control);
effect =
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
receiver_maps, p.feedback()),
receiver, effect, control);
Node* element = SafeLoadElement(kind, receiver, control, &effect, &k);
......@@ -977,11 +982,15 @@ Reduction JSCallReducer::ReduceArrayMap(Handle<JSFunction> function,
Node* node) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
CallParameters const& p = CallParametersOf(node->op());
// Try to determine the {receiver} map.
Node* receiver = NodeProperties::GetValueInput(node, 1);
......@@ -1095,9 +1104,10 @@ Reduction JSCallReducer::ReduceArrayMap(Handle<JSFunction> function,
graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
// Make sure the map hasn't changed during the iteration
effect = graph()->NewNode(
simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
effect, control);
effect =
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
receiver_maps, p.feedback()),
receiver, effect, control);
Node* element = SafeLoadElement(kind, receiver, control, &effect, &k);
......@@ -1155,11 +1165,15 @@ Reduction JSCallReducer::ReduceArrayFilter(Handle<JSFunction> function,
Node* node) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
CallParameters const& p = CallParametersOf(node->op());
// Try to determine the {receiver} map.
Node* receiver = NodeProperties::GetValueInput(node, 1);
Node* fncallback = node->op()->ValueInputCount() > 2
......@@ -1292,9 +1306,10 @@ Reduction JSCallReducer::ReduceArrayFilter(Handle<JSFunction> function,
}
// Make sure the map hasn't changed during the iteration.
effect = graph()->NewNode(
simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
effect, control);
effect =
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
receiver_maps, p.feedback()),
receiver, effect, control);
Node* element = SafeLoadElement(kind, receiver, control, &effect, &k);
......@@ -1378,11 +1393,15 @@ Reduction JSCallReducer::ReduceArrayFind(Handle<JSFunction> function,
Node* node) {
if (!FLAG_turbo_inline_array_builtins) return NoChange();
DCHECK_EQ(IrOpcode::kJSCall, node->opcode());
CallParameters const& p = CallParametersOf(node->op());
if (p.speculation_mode() == SpeculationMode::kDisallowSpeculation) {
return NoChange();
}
Node* outer_frame_state = NodeProperties::GetFrameStateInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* context = NodeProperties::GetContextInput(node);
CallParameters const& p = CallParametersOf(node->op());
// Try to determine the {receiver} map.
Node* receiver = NodeProperties::GetValueInput(node, 1);
......@@ -1471,9 +1490,10 @@ Reduction JSCallReducer::ReduceArrayFind(Handle<JSFunction> function,
effect =
graph()->NewNode(common()->Checkpoint(), frame_state, effect, control);
effect = graph()->NewNode(
simplified()->CheckMaps(CheckMapsFlag::kNone, receiver_maps), receiver,
effect, control);
effect =
graph()->NewNode(simplified()->CheckMaps(CheckMapsFlag::kNone,
receiver_maps, p.feedback()),
receiver, effect, control);
}
// Increment k for the next iteration.
......
......@@ -591,11 +591,6 @@ void InterpreterAssembler::IncrementCallCount(Node* feedback_vector,
// have to increment by 1 << {CallICNexus::CallCountField::kShift}.
Node* new_count =
SmiAdd(call_count, SmiConstant(1 << CallICNexus::CallCountField::kShift));
CSA_ASSERT(
this,
SmiEqual(SmiMod(new_count,
SmiConstant(1 << CallICNexus::CallCountField::kShift)),
SmiConstant(0)));
// Count is Smi, so we don't need a write barrier.
StoreFeedbackVectorSlot(feedback_vector, slot_id, new_count,
SKIP_WRITE_BARRIER, kPointerSize);
......
// 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 --opt
(function testForEach() {
function f(v,n,o) {
Object.freeze(o);
}
function g() {
[1,2,3].forEach(f);
}
g();
g();
%OptimizeFunctionOnNextCall(g);
g();
%OptimizeFunctionOnNextCall(g);
g();
assertOptimized(g);
})();
(function testFind() {
function f(v,n,o) {
Object.freeze(o);
return false;
}
function g() {
[1,2,3].find(f);
}
g();
g();
%OptimizeFunctionOnNextCall(g);
g();
%OptimizeFunctionOnNextCall(g);
g();
assertOptimized(g);
})();
(function testMap() {
function f(v,n,o) {
Object.freeze(o);
return false;
}
function g() {
[1,2,3].map(f);
}
g();
g();
%OptimizeFunctionOnNextCall(g);
g();
%OptimizeFunctionOnNextCall(g);
g();
assertOptimized(g);
})();
(function testFilter() {
function f(v,n,o) {
Object.freeze(o);
return true;
}
function g() {
[1,2,3].filter(f);
}
g();
g();
%OptimizeFunctionOnNextCall(g);
g();
%OptimizeFunctionOnNextCall(g);
g();
assertOptimized(g);
})();
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