[turbofan] Handle exceptional edges in ReduceArrayForEach.

This adds handling for exceptional control projections when lowering
calls to {Array.prototype.forEach} in the call reducer.

R=jarin@chromium.org
TEST=mjsunit/optimized-foreach
BUG=v8:1956

Change-Id: I282048b203814cbc1c90df983879578b210f92fb
Reviewed-on: https://chromium-review.googlesource.com/574542
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46834}
This commit is contained in:
Michael Starzinger 2017-07-24 10:33:34 +02:00 committed by Commit Bot
parent f4867154c4
commit d07365f9de
2 changed files with 42 additions and 4 deletions

View File

@ -524,9 +524,6 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
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());
@ -625,6 +622,16 @@ Reduction JSCallReducer::ReduceArrayForEach(Handle<JSFunction> function,
javascript()->Call(5, p.frequency()), fncallback, this_arg, element, k,
receiver, context, frame_state, effect, control);
// Update potential {IfException} uses of {node} to point to the above
// JavaScript call node within the loop instead.
Node* on_exception = nullptr;
if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
NodeProperties::ReplaceControlInput(on_exception, control);
NodeProperties::ReplaceEffectInput(on_exception, effect);
control = graph()->NewNode(common()->IfSuccess(), control);
Revisit(on_exception);
}
if (IsHoleyElementsKind(kind)) {
Node* after_call_control = control;
Node* after_call_effect = effect;

View File

@ -4,7 +4,7 @@
// Flags: --allow-natives-syntax --expose-gc --turbo-inline-array-builtins
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 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 = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
var c = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
@ -217,6 +217,37 @@ var c = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
lazyDeopt();
})();
// Call to a.forEach is done inside a try-catch block and the callback function
// being called throws into a deoptimized caller function.
(function TestThrowIntoDeoptimizedOuter() {
var a = [1,2,3,4];
var lazyDeopt = function(deopt) {
var sum = function(v,i,o) {
result += v;
if (i == 1 && deopt) {
%DeoptimizeFunction(lazyDeopt);
throw "some exception";
}
};
%NeverOptimizeFunction(sum);
var result = 0;
try {
a.forEach(sum);
} catch (e) {
assertEquals("some exception", e)
result += 100;
}
return result;
}
assertEquals(10, lazyDeopt(false));
assertEquals(10, lazyDeopt(false));
assertEquals(103, lazyDeopt(true));
assertEquals(103, lazyDeopt(true));
%OptimizeFunctionOnNextCall(lazyDeopt);
assertEquals(10, lazyDeopt(false));
assertEquals(103, lazyDeopt(true));
})();
(function() {
var re = /Array\.forEach/;
var lazyDeopt = function(deopt) {