[turbofan] Pin pure unreachable values to effect chain (in rep selection)

Currently, if we lower to a pure computation that is unreachable because
of some runtime check, we just rename it with DeadValue. This is
problematic if the pure computation gets later eliminated - that allows
the DeadValue node float above the check that makes it dead. As we
conservatively lower DeadValues to debug-break (i.e., crash), we
might induce crash where we should not.

With this CL, whenever we lower an impossible effectful node (i.e., with
Type::None) to a pure node in simplified lowering, we insert an
Unreachable node there (pinned to the effect chain) and mark the
impossible node dead (and make it depend on the Unreachable node).

Bug: chromium:910838
Change-Id: I218991c79b9e283a9dd5beb4d3f0c4664be76cb2
Reviewed-on: https://chromium-review.googlesource.com/c/1365274
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Jaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58066}
This commit is contained in:
Jaroslav Sevcik 2018-12-06 10:53:59 +01:00 committed by Commit Bot
parent f7f18b0f1e
commit f27ac2806c
3 changed files with 72 additions and 35 deletions

View File

@ -172,21 +172,6 @@ void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
}
}
void ChangeToPureOp(Node* node, const Operator* new_op) {
DCHECK(new_op->HasProperty(Operator::kPure));
if (node->op()->EffectInputCount() > 0) {
DCHECK_LT(0, node->op()->ControlInputCount());
// Disconnect the node from effect and control chains.
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
ReplaceEffectControlUses(node, effect, control);
node->TrimInputCount(new_op->ValueInputCount());
} else {
DCHECK_EQ(0, node->op()->ControlInputCount());
}
NodeProperties::ChangeOp(node, new_op);
}
bool CanOverflowSigned32(const Operator* op, Type left, Type right,
Zone* type_zone) {
// We assume the inputs are checked Signed32 (or known statically
@ -758,6 +743,31 @@ class RepresentationSelector {
!GetUpperBound(node->InputAt(1)).Maybe(type);
}
void ChangeToPureOp(Node* node, const Operator* new_op) {
DCHECK(new_op->HasProperty(Operator::kPure));
if (node->op()->EffectInputCount() > 0) {
DCHECK_LT(0, node->op()->ControlInputCount());
Node* control = NodeProperties::GetControlInput(node);
Node* effect = NodeProperties::GetEffectInput(node);
if (TypeOf(node).IsNone()) {
// If the node is unreachable, insert an Unreachable node and mark the
// value dead.
// TODO(jarin,tebbi) Find a way to unify/merge this insertion with
// InsertUnreachableIfNecessary.
Node* unreachable = effect = graph()->NewNode(
jsgraph_->common()->Unreachable(), effect, control);
new_op = jsgraph_->common()->DeadValue(GetInfo(node)->representation());
node->ReplaceInput(0, unreachable);
}
// Rewire the effect and control chains.
node->TrimInputCount(new_op->ValueInputCount());
ReplaceEffectControlUses(node, effect, control);
} else {
DCHECK_EQ(0, node->op()->ControlInputCount());
}
NodeProperties::ChangeOp(node, new_op);
}
// Converts input {index} of {node} according to given UseInfo {use},
// assuming the type of the input is {input_type}. If {input_type} is null,
// it takes the input from the input node {TypeOf(node->InputAt(index))}.
@ -1062,6 +1072,15 @@ class RepresentationSelector {
}
}
void MaskShiftOperand(Node* node, Type rhs_type) {
if (!rhs_type.Is(type_cache_.kZeroToThirtyOne)) {
Node* const rhs = NodeProperties::GetValueInput(node, 1);
node->ReplaceInput(1,
graph()->NewNode(jsgraph_->machine()->Word32And(), rhs,
jsgraph_->Int32Constant(0x1F)));
}
}
static MachineSemantic DeoptValueSemanticOf(Type type) {
// We only need signedness to do deopt correctly.
if (type.Is(Type::Signed32())) {
@ -2112,7 +2131,8 @@ class RepresentationSelector {
VisitBinop(node, UseInfo::TruncatingWord32(),
UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Shl());
}
return;
}
@ -2123,7 +2143,8 @@ class RepresentationSelector {
UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Shl());
}
return;
}
@ -2132,7 +2153,8 @@ class RepresentationSelector {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shl(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Shl());
}
return;
}
@ -2141,7 +2163,8 @@ class RepresentationSelector {
VisitBinop(node, UseInfo::TruncatingWord32(),
UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Sar());
}
return;
}
@ -2152,7 +2175,8 @@ class RepresentationSelector {
UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Sar());
}
return;
}
@ -2161,7 +2185,8 @@ class RepresentationSelector {
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Signed32());
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Sar(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Sar());
}
return;
}
@ -2170,7 +2195,8 @@ class RepresentationSelector {
VisitBinop(node, UseInfo::TruncatingWord32(),
UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Shr());
}
return;
}
@ -2199,14 +2225,16 @@ class RepresentationSelector {
UseInfo::TruncatingWord32(),
MachineRepresentation::kWord32);
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Shr());
}
return;
}
VisitBinop(node, CheckedUseInfoAsWord32FromHint(hint),
MachineRepresentation::kWord32, Type::Unsigned32());
if (lower()) {
lowering->DoShift(node, lowering->machine()->Word32Shr(), rhs_type);
MaskShiftOperand(node, rhs_type);
ChangeToPureOp(node, lowering->machine()->Word32Shr());
}
return;
}
@ -4000,16 +4028,6 @@ void SimplifiedLowering::DoMin(Node* node, Operator const* op,
NodeProperties::ChangeOp(node, common()->Select(rep));
}
void SimplifiedLowering::DoShift(Node* node, Operator const* op,
Type rhs_type) {
if (!rhs_type.Is(type_cache_.kZeroToThirtyOne)) {
Node* const rhs = NodeProperties::GetValueInput(node, 1);
node->ReplaceInput(1, graph()->NewNode(machine()->Word32And(), rhs,
jsgraph()->Int32Constant(0x1F)));
}
ChangeToPureOp(node, op);
}
void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
Node* const input = node->InputAt(0);
Node* const zero = jsgraph()->Int32Constant(0);

View File

@ -37,7 +37,6 @@ class V8_EXPORT_PRIVATE SimplifiedLowering final {
Node* node, RepresentationSelector* selector);
void DoJSToNumberOrNumericTruncatesToWord32(Node* node,
RepresentationSelector* selector);
void DoShift(Node* node, Operator const* op, Type rhs_type);
void DoIntegral32ToBit(Node* node);
void DoOrderedNumberToBit(Node* node);
void DoNumberToBit(Node* node);

View File

@ -0,0 +1,20 @@
// Copyright 2018 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
function f(b, s, x) {
if (!b) {
return (x ? b : s * undefined) ? 1 : 42;
}
}
function g(b, x) {
return f(b, 'abc', x);
}
f(false, 0, 0);
g(true, 0);
%OptimizeFunctionOnNextCall(g);
assertEquals(42, g(false, 0));