Revert "Reland^5 "[turbofan] eagerly prune None types and deadness from the graph""
This reverts commit ac0661b358
.
Reason for revert: Clusterfuzz unhappy: chromium:783019 chromium:783035
Original change's description:
> Reland^5 "[turbofan] eagerly prune None types and deadness from the graph"
>
> This gives up on earlier attempts to interpret DeadValue as a signal of
> unreachable code. This does not work because free-floating dead value
> nodes, and even pure branch nodes that use them, can get scheduled so
> early that they get reachable. Instead, we now eagerly remove branches
> that use DeadValue in DeadCodeElimination and replace DeadValue inputs
> to value phi nodes with dummy values.
>
> Reland of https://chromium-review.googlesource.com/715716
>
> Bug: chromium:741225 chromium:776256
> Change-Id: I251efd507c967d4a8882ad8fd2fd96c4185781fe
> Reviewed-on: https://chromium-review.googlesource.com/727893
> Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
> Reviewed-by: Jaroslav Sevcik <jarin@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#49188}
TBR=jarin@chromium.org,tebbi@chromium.org
Bug: chromium:741225 chromium:776256 chromium:783019 chromium:783035
Change-Id: I6a8fa3a08ce2824a858ae01817688e63ed1f442e
Reviewed-on: https://chromium-review.googlesource.com/758770
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49262}
This commit is contained in:
parent
d1193e3c6c
commit
c899637deb
@ -18,7 +18,9 @@ BranchElimination::BranchElimination(Editor* editor, JSGraph* js_graph,
|
||||
jsgraph_(js_graph),
|
||||
node_conditions_(zone, js_graph->graph()->NodeCount()),
|
||||
zone_(zone),
|
||||
dead_(js_graph->Dead()) {}
|
||||
dead_(js_graph->graph()->NewNode(js_graph->common()->Dead())) {
|
||||
NodeProperties::SetType(dead_, Type::None());
|
||||
}
|
||||
|
||||
BranchElimination::~BranchElimination() {}
|
||||
|
||||
|
@ -343,8 +343,6 @@ ZoneVector<MachineType> const* MachineTypesOf(Operator const* op) {
|
||||
|
||||
#define COMMON_CACHED_OP_LIST(V) \
|
||||
V(Dead, Operator::kFoldable, 0, 0, 0, 1, 1, 1) \
|
||||
V(DeadValue, Operator::kFoldable, 0, 0, 0, 1, 0, 0) \
|
||||
V(Unreachable, Operator::kFoldable, 0, 1, 1, 0, 1, 0) \
|
||||
V(IfTrue, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
|
||||
V(IfFalse, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
|
||||
V(IfSuccess, Operator::kKontrol, 0, 0, 1, 0, 0, 1) \
|
||||
|
@ -346,8 +346,6 @@ class V8_EXPORT_PRIVATE CommonOperatorBuilder final
|
||||
explicit CommonOperatorBuilder(Zone* zone);
|
||||
|
||||
const Operator* Dead();
|
||||
const Operator* DeadValue();
|
||||
const Operator* Unreachable();
|
||||
const Operator* End(size_t control_input_count);
|
||||
const Operator* Branch(BranchHint = BranchHint::kNone);
|
||||
const Operator* IfTrue();
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include "src/compiler/common-operator.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/js-operator.h"
|
||||
#include "src/compiler/node-properties.h"
|
||||
#include "src/compiler/operator-properties.h"
|
||||
|
||||
@ -15,38 +14,14 @@ namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
DeadCodeElimination::DeadCodeElimination(Editor* editor, Graph* graph,
|
||||
CommonOperatorBuilder* common,
|
||||
Zone* temp_zone)
|
||||
CommonOperatorBuilder* common)
|
||||
: AdvancedReducer(editor),
|
||||
graph_(graph),
|
||||
common_(common),
|
||||
dead_(graph->NewNode(common->Dead())),
|
||||
dead_value_(graph->NewNode(common->DeadValue())),
|
||||
zone_(temp_zone) {
|
||||
dead_(graph->NewNode(common->Dead())) {
|
||||
NodeProperties::SetType(dead_, Type::None());
|
||||
NodeProperties::SetType(dead_value_, Type::None());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// True if we can guarantee that {node} will never actually produce a value or
|
||||
// effect.
|
||||
bool NoReturn(Node* node) {
|
||||
return node->opcode() == IrOpcode::kDead ||
|
||||
node->opcode() == IrOpcode::kUnreachable ||
|
||||
node->opcode() == IrOpcode::kDeadValue ||
|
||||
NodeProperties::GetTypeOrAny(node)->IsNone();
|
||||
}
|
||||
|
||||
bool HasDeadInput(Node* node) {
|
||||
for (Node* input : node->inputs()) {
|
||||
if (NoReturn(input)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reduction DeadCodeElimination::Reduce(Node* node) {
|
||||
switch (node->opcode()) {
|
||||
case IrOpcode::kEnd:
|
||||
@ -56,34 +31,12 @@ Reduction DeadCodeElimination::Reduce(Node* node) {
|
||||
return ReduceLoopOrMerge(node);
|
||||
case IrOpcode::kLoopExit:
|
||||
return ReduceLoopExit(node);
|
||||
case IrOpcode::kUnreachable:
|
||||
case IrOpcode::kIfException:
|
||||
return ReduceUnreachableOrIfException(node);
|
||||
case IrOpcode::kPhi:
|
||||
return ReducePhi(node);
|
||||
case IrOpcode::kEffectPhi:
|
||||
return PropagateDeadControl(node);
|
||||
case IrOpcode::kDeoptimize:
|
||||
case IrOpcode::kReturn:
|
||||
case IrOpcode::kTerminate:
|
||||
return ReduceDeoptimizeOrReturnOrTerminate(node);
|
||||
case IrOpcode::kThrow:
|
||||
return PropagateDeadControl(node);
|
||||
case IrOpcode::kBranch:
|
||||
case IrOpcode::kSwitch:
|
||||
return ReduceBranchOrSwitch(node);
|
||||
default:
|
||||
return ReduceNode(node);
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::PropagateDeadControl(Node* node) {
|
||||
DCHECK_EQ(1, node->op()->ControlInputCount());
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
if (control->opcode() == IrOpcode::kDead) return Replace(control);
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReduceEnd(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kEnd, node->opcode());
|
||||
@ -187,105 +140,13 @@ Reduction DeadCodeElimination::RemoveLoopExit(Node* node) {
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReduceNode(Node* node) {
|
||||
DCHECK(!IrOpcode::IsGraphTerminator(node->opcode()));
|
||||
int const effect_input_count = node->op()->EffectInputCount();
|
||||
// If {node} has exactly one control input and this is {Dead},
|
||||
// replace {node} with {Dead}.
|
||||
int const control_input_count = node->op()->ControlInputCount();
|
||||
DCHECK_LE(control_input_count, 1);
|
||||
if (control_input_count == 1) {
|
||||
Reduction reduction = PropagateDeadControl(node);
|
||||
if (reduction.Changed()) return reduction;
|
||||
}
|
||||
if (effect_input_count == 0 &&
|
||||
(control_input_count == 0 || node->op()->ControlOutputCount() == 0)) {
|
||||
return ReducePureNode(node);
|
||||
}
|
||||
if (effect_input_count > 0) {
|
||||
return ReduceEffectNode(node);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReducePhi(Node* node) {
|
||||
DCHECK_EQ(IrOpcode::kPhi, node->opcode());
|
||||
Reduction reduction = PropagateDeadControl(node);
|
||||
if (reduction.Changed()) return reduction;
|
||||
if (PhiRepresentationOf(node->op()) == MachineRepresentation::kNone ||
|
||||
NodeProperties::GetTypeOrAny(node)->IsNone()) {
|
||||
return Replace(dead_value());
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReducePureNode(Node* node) {
|
||||
DCHECK_EQ(0, node->op()->EffectInputCount());
|
||||
int input_count = node->op()->ValueInputCount();
|
||||
for (int i = 0; i < input_count; ++i) {
|
||||
Node* input = NodeProperties::GetValueInput(node, i);
|
||||
if (NoReturn(input)) {
|
||||
return Replace(dead_value());
|
||||
}
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReduceUnreachableOrIfException(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kUnreachable ||
|
||||
node->opcode() == IrOpcode::kIfException);
|
||||
Reduction reduction = PropagateDeadControl(node);
|
||||
if (reduction.Changed()) return reduction;
|
||||
Node* effect = NodeProperties::GetEffectInput(node, 0);
|
||||
if (effect->opcode() == IrOpcode::kDead) {
|
||||
return Replace(effect);
|
||||
}
|
||||
if (effect->opcode() == IrOpcode::kUnreachable) {
|
||||
RelaxEffectsAndControls(node);
|
||||
return Replace(dead_value());
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReduceEffectNode(Node* node) {
|
||||
DCHECK_EQ(1, node->op()->EffectInputCount());
|
||||
Node* effect = NodeProperties::GetEffectInput(node, 0);
|
||||
if (effect->opcode() == IrOpcode::kDead) {
|
||||
return Replace(effect);
|
||||
}
|
||||
if (HasDeadInput(node)) {
|
||||
if (effect->opcode() == IrOpcode::kUnreachable) {
|
||||
RelaxEffectsAndControls(node);
|
||||
return Replace(dead_value());
|
||||
}
|
||||
|
||||
Node* control = node->op()->ControlInputCount() == 1
|
||||
? NodeProperties::GetControlInput(node, 0)
|
||||
: graph()->start();
|
||||
Node* unreachable =
|
||||
graph()->NewNode(common()->Unreachable(), effect, control);
|
||||
ReplaceWithValue(node, dead_value(), node, control);
|
||||
return Replace(unreachable);
|
||||
}
|
||||
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReduceDeoptimizeOrReturnOrTerminate(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kDeoptimize ||
|
||||
node->opcode() == IrOpcode::kReturn ||
|
||||
node->opcode() == IrOpcode::kTerminate);
|
||||
Reduction reduction = PropagateDeadControl(node);
|
||||
if (reduction.Changed()) return reduction;
|
||||
if (HasDeadInput(node)) {
|
||||
Node* effect = NodeProperties::GetEffectInput(node, 0);
|
||||
Node* control = NodeProperties::GetControlInput(node, 0);
|
||||
if (effect->opcode() != IrOpcode::kUnreachable) {
|
||||
effect = graph()->NewNode(common()->Unreachable(), effect, control);
|
||||
}
|
||||
node->TrimInputCount(2);
|
||||
node->ReplaceInput(0, effect);
|
||||
node->ReplaceInput(1, control);
|
||||
NodeProperties::ChangeOp(node, common()->Throw());
|
||||
return Changed(node);
|
||||
}
|
||||
if (control_input_count == 0) return NoChange();
|
||||
DCHECK_EQ(1, control_input_count);
|
||||
Node* control = NodeProperties::GetControlInput(node);
|
||||
if (control->opcode() == IrOpcode::kDead) return Replace(control);
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
@ -299,27 +160,6 @@ Reduction DeadCodeElimination::ReduceLoopExit(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
Reduction DeadCodeElimination::ReduceBranchOrSwitch(Node* node) {
|
||||
DCHECK(node->opcode() == IrOpcode::kBranch ||
|
||||
node->opcode() == IrOpcode::kSwitch);
|
||||
Reduction reduction = PropagateDeadControl(node);
|
||||
if (reduction.Changed()) return reduction;
|
||||
Node* condition = NodeProperties::GetValueInput(node, 0);
|
||||
if (condition->opcode() == IrOpcode::kDeadValue) {
|
||||
// Branches or switches on {DeadValue} must originate from unreachable code
|
||||
// and cannot matter. Due to schedule freedom between the effect and the
|
||||
// control chain, they might still appear in reachable code. Remove them by
|
||||
// always choosing the first projection.
|
||||
size_t const projection_cnt = node->op()->ControlOutputCount();
|
||||
Node** projections = zone_->NewArray<Node*>(projection_cnt);
|
||||
NodeProperties::CollectControlProjections(node, projections,
|
||||
projection_cnt);
|
||||
Replace(projections[0], NodeProperties::GetControlInput(node));
|
||||
return Replace(dead());
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
void DeadCodeElimination::TrimMergeOrPhi(Node* node, int size) {
|
||||
const Operator* const op = common()->ResizeMergeOrPhi(node->op(), size);
|
||||
node->TrimInputCount(OperatorProperties::GetTotalInputCount(op));
|
||||
|
@ -16,20 +16,15 @@ namespace compiler {
|
||||
// Forward declarations.
|
||||
class CommonOperatorBuilder;
|
||||
|
||||
// Propagates {Dead} control and {DeadValue} values through the graph and
|
||||
// thereby removes dead code. When {DeadValue} hits the effect chain, a crashing
|
||||
// {Unreachable} node is inserted and the rest of the effect chain is collapsed.
|
||||
// We wait for the {EffectControlLinearizer} to connect {Unreachable} nodes to
|
||||
// the graph end, since this is much easier if there is no floating control.
|
||||
// We detect dead values based on types, pruning uses of DeadValue except for
|
||||
// uses by phi. These remaining uses are eliminated in the
|
||||
// {EffectControlLinearizer}, where they are replaced with dummy values.
|
||||
// In contrast to {DeadValue}, {Dead} can never remain in the graph.
|
||||
// Propagates {Dead} control through the graph and thereby removes dead code.
|
||||
// Note that this does not include trimming dead uses from the graph, and it
|
||||
// also does not include detecting dead code by any other means than seeing a
|
||||
// {Dead} control input; that is left to other reducers.
|
||||
class V8_EXPORT_PRIVATE DeadCodeElimination final
|
||||
: public NON_EXPORTED_BASE(AdvancedReducer) {
|
||||
public:
|
||||
DeadCodeElimination(Editor* editor, Graph* graph,
|
||||
CommonOperatorBuilder* common, Zone* temp_zone);
|
||||
CommonOperatorBuilder* common);
|
||||
~DeadCodeElimination() final {}
|
||||
|
||||
const char* reducer_name() const override { return "DeadCodeElimination"; }
|
||||
@ -41,28 +36,18 @@ class V8_EXPORT_PRIVATE DeadCodeElimination final
|
||||
Reduction ReduceLoopOrMerge(Node* node);
|
||||
Reduction ReduceLoopExit(Node* node);
|
||||
Reduction ReduceNode(Node* node);
|
||||
Reduction ReducePhi(Node* node);
|
||||
Reduction ReducePureNode(Node* node);
|
||||
Reduction ReduceUnreachableOrIfException(Node* node);
|
||||
Reduction ReduceEffectNode(Node* node);
|
||||
Reduction ReduceDeoptimizeOrReturnOrTerminate(Node* node);
|
||||
Reduction ReduceBranchOrSwitch(Node* node);
|
||||
|
||||
Reduction RemoveLoopExit(Node* node);
|
||||
Reduction PropagateDeadControl(Node* node);
|
||||
|
||||
void TrimMergeOrPhi(Node* node, int size);
|
||||
|
||||
Graph* graph() const { return graph_; }
|
||||
CommonOperatorBuilder* common() const { return common_; }
|
||||
Node* dead() const { return dead_; }
|
||||
Node* dead_value() const { return dead_value_; }
|
||||
|
||||
Graph* const graph_;
|
||||
CommonOperatorBuilder* const common_;
|
||||
Node* const dead_;
|
||||
Node* const dead_value_;
|
||||
Zone* zone_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DeadCodeElimination);
|
||||
};
|
||||
|
@ -76,19 +76,8 @@ struct PendingEffectPhi {
|
||||
: effect_phi(effect_phi), block(block) {}
|
||||
};
|
||||
|
||||
void ConnectUnreachableToEnd(Node* effect, Node* control, JSGraph* jsgraph) {
|
||||
Graph* graph = jsgraph->graph();
|
||||
CommonOperatorBuilder* common = jsgraph->common();
|
||||
if (effect->opcode() == IrOpcode::kDead) return;
|
||||
if (effect->opcode() != IrOpcode::kUnreachable) {
|
||||
effect = graph->NewNode(common->Unreachable(), effect, control);
|
||||
}
|
||||
Node* throw_node = graph->NewNode(common->Throw(), effect, control);
|
||||
NodeProperties::MergeControlToEnd(graph, common, throw_node);
|
||||
}
|
||||
|
||||
void UpdateEffectPhi(Node* node, BasicBlock* block,
|
||||
BlockEffectControlMap* block_effects, JSGraph* jsgraph) {
|
||||
BlockEffectControlMap* block_effects) {
|
||||
// Update all inputs to an effect phi with the effects from the given
|
||||
// block->effect map.
|
||||
DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
|
||||
@ -99,9 +88,8 @@ void UpdateEffectPhi(Node* node, BasicBlock* block,
|
||||
BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
|
||||
const BlockEffectControlData& block_effect =
|
||||
block_effects->For(predecessor, block);
|
||||
Node* effect = block_effect.current_effect;
|
||||
if (input != effect) {
|
||||
node->ReplaceInput(i, effect);
|
||||
if (input != block_effect.current_effect) {
|
||||
node->ReplaceInput(i, block_effect.current_effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -315,29 +303,6 @@ void TryCloneBranch(Node* node, BasicBlock* block, Zone* temp_zone,
|
||||
cond->Kill();
|
||||
merge->Kill();
|
||||
}
|
||||
|
||||
Node* DummyValue(JSGraph* jsgraph, MachineRepresentation rep) {
|
||||
switch (rep) {
|
||||
case MachineRepresentation::kTagged:
|
||||
case MachineRepresentation::kTaggedSigned:
|
||||
return jsgraph->SmiConstant(0xdead);
|
||||
case MachineRepresentation::kTaggedPointer:
|
||||
return jsgraph->TheHoleConstant();
|
||||
case MachineRepresentation::kWord64:
|
||||
return jsgraph->Int64Constant(0xdead);
|
||||
case MachineRepresentation::kWord32:
|
||||
return jsgraph->Int32Constant(0xdead);
|
||||
case MachineRepresentation::kFloat64:
|
||||
return jsgraph->Float64Constant(0xdead);
|
||||
case MachineRepresentation::kFloat32:
|
||||
return jsgraph->Float32Constant(0xdead);
|
||||
case MachineRepresentation::kBit:
|
||||
return jsgraph->Int32Constant(0);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void EffectControlLinearizer::Run() {
|
||||
@ -365,32 +330,29 @@ void EffectControlLinearizer::Run() {
|
||||
instr++;
|
||||
|
||||
// Iterate over the phis and update the effect phis.
|
||||
Node* effect_phi = nullptr;
|
||||
Node* effect = nullptr;
|
||||
Node* terminate = nullptr;
|
||||
int predecessor_count = static_cast<int>(block->PredecessorCount());
|
||||
for (; instr < block->NodeCount(); instr++) {
|
||||
Node* node = block->NodeAt(instr);
|
||||
// Only go through the phis and effect phis.
|
||||
if (node->opcode() == IrOpcode::kEffectPhi) {
|
||||
// There should be at most one effect phi in a block.
|
||||
DCHECK_NULL(effect_phi);
|
||||
DCHECK_NULL(effect);
|
||||
// IfException blocks should not have effect phis.
|
||||
DCHECK_NE(IrOpcode::kIfException, control->opcode());
|
||||
effect_phi = node;
|
||||
} else if (node->opcode() == IrOpcode::kPhi) {
|
||||
DCHECK_EQ(predecessor_count, node->op()->ValueInputCount());
|
||||
for (int i = 0; i < predecessor_count; ++i) {
|
||||
if (NodeProperties::GetValueInput(node, i)->opcode() ==
|
||||
IrOpcode::kDeadValue) {
|
||||
// Phi uses of {DeadValue} must originate from unreachable code. Due
|
||||
// to schedule freedom between the effect and the control chain,
|
||||
// they might still appear in reachable code. So we replace them
|
||||
// with a dummy value.
|
||||
NodeProperties::ReplaceValueInput(
|
||||
node, DummyValue(jsgraph(), PhiRepresentationOf(node->op())),
|
||||
i);
|
||||
}
|
||||
effect = node;
|
||||
|
||||
// Make sure we update the inputs to the incoming blocks' effects.
|
||||
if (HasIncomingBackEdges(block)) {
|
||||
// In case of loops, we do not update the effect phi immediately
|
||||
// because the back predecessor has not been handled yet. We just
|
||||
// record the effect phi for later processing.
|
||||
pending_effect_phis.push_back(PendingEffectPhi(node, block));
|
||||
} else {
|
||||
UpdateEffectPhi(node, block, &block_effects);
|
||||
}
|
||||
} else if (node->opcode() == IrOpcode::kPhi) {
|
||||
// Just skip phis.
|
||||
} else if (node->opcode() == IrOpcode::kTerminate) {
|
||||
DCHECK_NULL(terminate);
|
||||
terminate = node;
|
||||
@ -399,28 +361,9 @@ void EffectControlLinearizer::Run() {
|
||||
}
|
||||
}
|
||||
|
||||
if (effect_phi) {
|
||||
// Make sure we update the inputs to the incoming blocks' effects.
|
||||
if (HasIncomingBackEdges(block)) {
|
||||
// In case of loops, we do not update the effect phi immediately
|
||||
// because the back predecessor has not been handled yet. We just
|
||||
// record the effect phi for later processing.
|
||||
pending_effect_phis.push_back(PendingEffectPhi(effect_phi, block));
|
||||
} else {
|
||||
UpdateEffectPhi(effect_phi, block, &block_effects, jsgraph());
|
||||
}
|
||||
}
|
||||
|
||||
Node* effect = effect_phi;
|
||||
if (effect == nullptr) {
|
||||
// There was no effect phi.
|
||||
|
||||
// Since a loop should have at least a StackCheck, only loops in
|
||||
// unreachable code can have no effect phi.
|
||||
DCHECK_IMPLIES(
|
||||
HasIncomingBackEdges(block),
|
||||
block_effects.For(block->PredecessorAt(0), block)
|
||||
.current_effect->opcode() == IrOpcode::kUnreachable);
|
||||
DCHECK(!HasIncomingBackEdges(block));
|
||||
if (block == schedule()->start()) {
|
||||
// Start block => effect is start.
|
||||
DCHECK_EQ(graph()->start(), control);
|
||||
@ -433,11 +376,11 @@ void EffectControlLinearizer::Run() {
|
||||
} else {
|
||||
// If all the predecessors have the same effect, we can use it as our
|
||||
// current effect.
|
||||
for (size_t i = 0; i < block->PredecessorCount(); ++i) {
|
||||
const BlockEffectControlData& data =
|
||||
block_effects.For(block->PredecessorAt(i), block);
|
||||
if (!effect) effect = data.current_effect;
|
||||
if (data.current_effect != effect) {
|
||||
effect =
|
||||
block_effects.For(block->PredecessorAt(0), block).current_effect;
|
||||
for (size_t i = 1; i < block->PredecessorCount(); ++i) {
|
||||
if (block_effects.For(block->PredecessorAt(i), block)
|
||||
.current_effect != effect) {
|
||||
effect = nullptr;
|
||||
break;
|
||||
}
|
||||
@ -456,7 +399,7 @@ void EffectControlLinearizer::Run() {
|
||||
if (control->opcode() == IrOpcode::kLoop) {
|
||||
pending_effect_phis.push_back(PendingEffectPhi(effect, block));
|
||||
} else {
|
||||
UpdateEffectPhi(effect, block, &block_effects, jsgraph());
|
||||
UpdateEffectPhi(effect, block, &block_effects);
|
||||
}
|
||||
} else if (control->opcode() == IrOpcode::kIfException) {
|
||||
// The IfException is connected into the effect chain, so we need
|
||||
@ -533,14 +476,14 @@ void EffectControlLinearizer::Run() {
|
||||
}
|
||||
}
|
||||
|
||||
for (BasicBlock* pending_block_control : pending_block_controls) {
|
||||
UpdateBlockControl(pending_block_control, &block_effects);
|
||||
}
|
||||
// Update the incoming edges of the effect phis that could not be processed
|
||||
// during the first pass (because they could have incoming back edges).
|
||||
for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) {
|
||||
UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
|
||||
&block_effects, jsgraph());
|
||||
&block_effects);
|
||||
}
|
||||
for (BasicBlock* pending_block_control : pending_block_controls) {
|
||||
UpdateBlockControl(pending_block_control, &block_effects);
|
||||
}
|
||||
}
|
||||
|
||||
@ -626,13 +569,6 @@ void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
|
||||
if (node->op()->ControlOutputCount() > 0) {
|
||||
*control = node;
|
||||
}
|
||||
|
||||
// Break the effect chain on {Unreachable} and reconnect to the graph end.
|
||||
// Mark the following code for deletion by connecting to the {Dead} node.
|
||||
if (node->opcode() == IrOpcode::kUnreachable) {
|
||||
ConnectUnreachableToEnd(*effect, *control, jsgraph());
|
||||
*effect = *control = jsgraph()->Dead();
|
||||
}
|
||||
}
|
||||
|
||||
bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
|
||||
|
@ -1120,9 +1120,6 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
case IrOpcode::kDebugBreak:
|
||||
VisitDebugBreak(node);
|
||||
return;
|
||||
case IrOpcode::kUnreachable:
|
||||
VisitUnreachable(node);
|
||||
return;
|
||||
case IrOpcode::kComment:
|
||||
VisitComment(node);
|
||||
return;
|
||||
@ -2763,11 +2760,6 @@ void InstructionSelector::VisitDebugBreak(Node* node) {
|
||||
Emit(kArchDebugBreak, g.NoOutput());
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitUnreachable(Node* node) {
|
||||
OperandGenerator g(this);
|
||||
Emit(kArchDebugBreak, g.NoOutput());
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitComment(Node* node) {
|
||||
OperandGenerator g(this);
|
||||
InstructionOperand operand(g.UseImmediate(node));
|
||||
|
@ -348,7 +348,6 @@ class V8_EXPORT_PRIVATE InstructionSelector final {
|
||||
void VisitReturn(Node* ret);
|
||||
void VisitThrow(Node* node);
|
||||
void VisitRetain(Node* node);
|
||||
void VisitUnreachable(Node* node);
|
||||
|
||||
void EmitPrepareArguments(ZoneVector<compiler::PushParameter>* arguments,
|
||||
const CallDescriptor* descriptor, Node* node);
|
||||
|
@ -305,9 +305,6 @@ Node* JSGraph::Dead() {
|
||||
return CACHED(kDead, graph()->NewNode(common()->Dead()));
|
||||
}
|
||||
|
||||
Node* JSGraph::DeadValue() {
|
||||
return CACHED(kDeadValue, graph()->NewNode(common()->DeadValue()));
|
||||
}
|
||||
|
||||
void JSGraph::GetCachedNodes(NodeVector* nodes) {
|
||||
cache_.GetCachedNodes(nodes);
|
||||
|
@ -155,9 +155,6 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
// Create a control node that serves as dependency for dead nodes.
|
||||
Node* Dead();
|
||||
|
||||
// Sentinel for a value resulting from unreachable computations.
|
||||
Node* DeadValue();
|
||||
|
||||
CommonOperatorBuilder* common() const { return common_; }
|
||||
JSOperatorBuilder* javascript() const { return javascript_; }
|
||||
SimplifiedOperatorBuilder* simplified() const { return simplified_; }
|
||||
@ -199,7 +196,6 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
|
||||
kEmptyStateValues,
|
||||
kSingleDeadTypedStateValues,
|
||||
kDead,
|
||||
kDeadValue,
|
||||
kNumCachedNodes // Must remain last.
|
||||
};
|
||||
|
||||
|
@ -100,7 +100,6 @@ void MemoryOptimizer::VisitNode(Node* node, AllocationState const* state) {
|
||||
case IrOpcode::kRetain:
|
||||
case IrOpcode::kUnsafePointerAdd:
|
||||
case IrOpcode::kDebugBreak:
|
||||
case IrOpcode::kUnreachable:
|
||||
return VisitOtherEffect(node, state);
|
||||
default:
|
||||
break;
|
||||
|
@ -79,8 +79,6 @@
|
||||
#define COMMON_OP_LIST(V) \
|
||||
CONSTANT_OP_LIST(V) \
|
||||
INNER_OP_LIST(V) \
|
||||
V(Unreachable) \
|
||||
V(DeadValue) \
|
||||
V(Dead)
|
||||
|
||||
// Opcodes for JavaScript operators.
|
||||
|
@ -947,7 +947,7 @@ PipelineWasmCompilationJob::ExecuteJobImpl() {
|
||||
PipelineRunScope scope(data, "Wasm optimization");
|
||||
JSGraphReducer graph_reducer(data->jsgraph(), scope.zone());
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), scope.zone());
|
||||
data->common());
|
||||
ValueNumberingReducer value_numbering(scope.zone(), data->graph()->zone());
|
||||
MachineOperatorReducer machine_reducer(data->jsgraph(), asmjs_origin_);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
@ -1091,7 +1091,7 @@ struct InliningPhase {
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
data->common());
|
||||
CheckpointElimination checkpoint_elimination(&graph_reducer);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->common(), data->machine());
|
||||
@ -1185,7 +1185,7 @@ struct TypedLoweringPhase {
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
data->common());
|
||||
JSBuiltinReducer builtin_reducer(
|
||||
&graph_reducer, data->jsgraph(),
|
||||
data->info()->dependencies(), data->native_context());
|
||||
@ -1298,7 +1298,7 @@ struct EarlyOptimizationPhase {
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
data->common());
|
||||
SimplifiedOperatorReducer simple_reducer(&graph_reducer, data->jsgraph());
|
||||
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
@ -1329,48 +1329,50 @@ struct EffectControlLinearizationPhase {
|
||||
static const char* phase_name() { return "effect linearization"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
{
|
||||
// The scheduler requires the graphs to be trimmed, so trim now.
|
||||
// TODO(jarin) Remove the trimming once the scheduler can handle untrimmed
|
||||
// graphs.
|
||||
GraphTrimmer trimmer(temp_zone, data->graph());
|
||||
NodeVector roots(temp_zone);
|
||||
data->jsgraph()->GetCachedNodes(&roots);
|
||||
trimmer.TrimGraph(roots.begin(), roots.end());
|
||||
// The scheduler requires the graphs to be trimmed, so trim now.
|
||||
// TODO(jarin) Remove the trimming once the scheduler can handle untrimmed
|
||||
// graphs.
|
||||
GraphTrimmer trimmer(temp_zone, data->graph());
|
||||
NodeVector roots(temp_zone);
|
||||
data->jsgraph()->GetCachedNodes(&roots);
|
||||
trimmer.TrimGraph(roots.begin(), roots.end());
|
||||
|
||||
// Schedule the graph without node splitting so that we can
|
||||
// fix the effect and control flow for nodes with low-level side
|
||||
// effects (such as changing representation to tagged or
|
||||
// 'floating' allocation regions.)
|
||||
Schedule* schedule = Scheduler::ComputeSchedule(temp_zone, data->graph(),
|
||||
Scheduler::kTempSchedule);
|
||||
if (FLAG_turbo_verify) ScheduleVerifier::Run(schedule);
|
||||
TraceSchedule(data->info(), schedule);
|
||||
// Schedule the graph without node splitting so that we can
|
||||
// fix the effect and control flow for nodes with low-level side
|
||||
// effects (such as changing representation to tagged or
|
||||
// 'floating' allocation regions.)
|
||||
Schedule* schedule = Scheduler::ComputeSchedule(temp_zone, data->graph(),
|
||||
Scheduler::kTempSchedule);
|
||||
if (FLAG_turbo_verify) ScheduleVerifier::Run(schedule);
|
||||
TraceSchedule(data->info(), schedule);
|
||||
|
||||
// Post-pass for wiring the control/effects
|
||||
// - connect allocating representation changes into the control&effect
|
||||
// chains and lower them,
|
||||
// - get rid of the region markers,
|
||||
// - introduce effect phis and rewire effects to get SSA again.
|
||||
EffectControlLinearizer linearizer(data->jsgraph(), schedule, temp_zone,
|
||||
data->source_positions());
|
||||
linearizer.Run();
|
||||
}
|
||||
{
|
||||
// The {EffectControlLinearizer} might leave {Dead} nodes behind, so we
|
||||
// run {DeadCodeElimination} to prune these parts of the graph.
|
||||
// Also, the following store-store elimination phase greatly benefits from
|
||||
// doing a common operator reducer and dead code elimination just before
|
||||
// it, to eliminate conditional deopts with a constant condition.
|
||||
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->common(), data->machine());
|
||||
AddReducer(data, &graph_reducer, &dead_code_elimination);
|
||||
AddReducer(data, &graph_reducer, &common_reducer);
|
||||
graph_reducer.ReduceGraph();
|
||||
}
|
||||
// Post-pass for wiring the control/effects
|
||||
// - connect allocating representation changes into the control&effect
|
||||
// chains and lower them,
|
||||
// - get rid of the region markers,
|
||||
// - introduce effect phis and rewire effects to get SSA again.
|
||||
EffectControlLinearizer linearizer(data->jsgraph(), schedule, temp_zone,
|
||||
data->source_positions());
|
||||
linearizer.Run();
|
||||
}
|
||||
};
|
||||
|
||||
// The store-store elimination greatly benefits from doing a common operator
|
||||
// reducer and dead code elimination just before it, to eliminate conditional
|
||||
// deopts with a constant condition.
|
||||
|
||||
struct DeadCodeEliminationPhase {
|
||||
static const char* phase_name() { return "dead code elimination"; }
|
||||
|
||||
void Run(PipelineData* data, Zone* temp_zone) {
|
||||
JSGraphReducer graph_reducer(data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common());
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
data->common(), data->machine());
|
||||
AddReducer(data, &graph_reducer, &dead_code_elimination);
|
||||
AddReducer(data, &graph_reducer, &common_reducer);
|
||||
graph_reducer.ReduceGraph();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1395,7 +1397,7 @@ struct LoadEliminationPhase {
|
||||
BranchElimination branch_condition_elimination(&graph_reducer,
|
||||
data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
data->common());
|
||||
RedundancyElimination redundancy_elimination(&graph_reducer, temp_zone);
|
||||
LoadElimination load_elimination(&graph_reducer, data->jsgraph(),
|
||||
temp_zone);
|
||||
@ -1438,7 +1440,7 @@ struct LateOptimizationPhase {
|
||||
BranchElimination branch_condition_elimination(&graph_reducer,
|
||||
data->jsgraph(), temp_zone);
|
||||
DeadCodeElimination dead_code_elimination(&graph_reducer, data->graph(),
|
||||
data->common(), temp_zone);
|
||||
data->common());
|
||||
ValueNumberingReducer value_numbering(temp_zone, data->graph()->zone());
|
||||
MachineOperatorReducer machine_reducer(data->jsgraph());
|
||||
CommonOperatorReducer common_reducer(&graph_reducer, data->graph(),
|
||||
@ -1893,6 +1895,9 @@ bool PipelineImpl::OptimizeGraph(Linkage* linkage) {
|
||||
Run<EffectControlLinearizationPhase>();
|
||||
RunPrintAndVerify("Effect and control linearized", true);
|
||||
|
||||
Run<DeadCodeEliminationPhase>();
|
||||
RunPrintAndVerify("Dead code elimination", true);
|
||||
|
||||
if (FLAG_turbo_store_elimination) {
|
||||
Run<StoreStoreEliminationPhase>();
|
||||
RunPrintAndVerify("Store-store elimination", true);
|
||||
|
@ -216,7 +216,8 @@ Node* RepresentationChanger::GetTaggedSignedRepresentationFor(
|
||||
const Operator* op;
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->Constant(0);
|
||||
} else if (IsWord(output_rep)) {
|
||||
if (output_type->Is(Type::Signed31())) {
|
||||
op = simplified()->ChangeInt31ToTaggedSigned();
|
||||
@ -334,7 +335,8 @@ Node* RepresentationChanger::GetTaggedPointerRepresentationFor(
|
||||
Operator const* op;
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->TheHoleConstant();
|
||||
} else if (output_rep == MachineRepresentation::kBit) {
|
||||
if (output_type->Is(Type::Boolean())) {
|
||||
op = simplified()->ChangeBitToTagged();
|
||||
@ -411,7 +413,8 @@ Node* RepresentationChanger::GetTaggedRepresentationFor(
|
||||
const Operator* op;
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->TheHoleConstant();
|
||||
} else if (output_rep == MachineRepresentation::kBit) {
|
||||
if (output_type->Is(Type::Boolean())) {
|
||||
op = simplified()->ChangeBitToTagged();
|
||||
@ -489,7 +492,8 @@ Node* RepresentationChanger::GetFloat32RepresentationFor(
|
||||
const Operator* op = nullptr;
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->Float32Constant(0.0f);
|
||||
} else if (IsWord(output_rep)) {
|
||||
if (output_type->Is(Type::Signed32())) {
|
||||
// int32 -> float64 -> float32
|
||||
@ -549,7 +553,8 @@ Node* RepresentationChanger::GetFloat64RepresentationFor(
|
||||
const Operator* op = nullptr;
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->Float64Constant(0.0);
|
||||
} else if (IsWord(output_rep)) {
|
||||
if (output_type->Is(Type::Signed32())) {
|
||||
op = machine()->ChangeInt32ToFloat64();
|
||||
@ -626,7 +631,8 @@ Node* RepresentationChanger::GetWord32RepresentationFor(
|
||||
const Operator* op = nullptr;
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->Int32Constant(0);
|
||||
} else if (output_rep == MachineRepresentation::kBit) {
|
||||
return node; // Sloppy comparison -> word32
|
||||
} else if (output_rep == MachineRepresentation::kFloat64) {
|
||||
@ -762,7 +768,8 @@ Node* RepresentationChanger::GetBitRepresentationFor(
|
||||
const Operator* op;
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->Int32Constant(0);
|
||||
} else if (output_rep == MachineRepresentation::kTagged ||
|
||||
output_rep == MachineRepresentation::kTaggedPointer) {
|
||||
if (output_type->Is(Type::BooleanOrNullOrUndefined())) {
|
||||
@ -807,7 +814,8 @@ Node* RepresentationChanger::GetWord64RepresentationFor(
|
||||
Node* node, MachineRepresentation output_rep, Type* output_type) {
|
||||
if (output_type->Is(Type::None())) {
|
||||
// This is an impossible value; it should not be used at runtime.
|
||||
return jsgraph()->DeadValue();
|
||||
// We just provide a dummy value here.
|
||||
return jsgraph()->Int64Constant(0);
|
||||
} else if (output_rep == MachineRepresentation::kBit) {
|
||||
return node; // Sloppy comparison -> word64
|
||||
}
|
||||
|
@ -3027,7 +3027,6 @@ class RepresentationSelector {
|
||||
case IrOpcode::kOsrValue:
|
||||
case IrOpcode::kArgumentsElementsState:
|
||||
case IrOpcode::kArgumentsLengthState:
|
||||
case IrOpcode::kUnreachable:
|
||||
case IrOpcode::kRuntimeAbort:
|
||||
// All JavaScript operators except JSToNumber have uniform handling.
|
||||
#define OPCODE_CASE(name) case IrOpcode::k##name:
|
||||
@ -3044,8 +3043,7 @@ class RepresentationSelector {
|
||||
VisitInputs(node);
|
||||
// Assume the output is tagged.
|
||||
return SetOutput(node, MachineRepresentation::kTagged);
|
||||
case IrOpcode::kDeadValue:
|
||||
return SetOutput(node, MachineRepresentation::kNone);
|
||||
|
||||
default:
|
||||
V8_Fatal(
|
||||
__FILE__, __LINE__,
|
||||
|
@ -896,10 +896,6 @@ Type* Typer::Visitor::TypeTypeGuard(Node* node) {
|
||||
|
||||
Type* Typer::Visitor::TypeDead(Node* node) { return Type::None(); }
|
||||
|
||||
Type* Typer::Visitor::TypeDeadValue(Node* node) { return Type::None(); }
|
||||
|
||||
Type* Typer::Visitor::TypeUnreachable(Node* node) { UNREACHABLE(); }
|
||||
|
||||
// JS comparison operators.
|
||||
|
||||
|
||||
|
@ -236,11 +236,6 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kDead:
|
||||
// Dead is never connected to the graph.
|
||||
UNREACHABLE();
|
||||
case IrOpcode::kDeadValue:
|
||||
CheckTypeIs(node, Type::None());
|
||||
break;
|
||||
case IrOpcode::kUnreachable:
|
||||
CheckNotTyped(node);
|
||||
break;
|
||||
case IrOpcode::kBranch: {
|
||||
// Branch uses are IfTrue and IfFalse.
|
||||
@ -1864,8 +1859,7 @@ void Verifier::VerifyNode(Node* node) {
|
||||
Node* input = NodeProperties::GetFrameStateInput(node);
|
||||
DCHECK(input->opcode() == IrOpcode::kFrameState ||
|
||||
input->opcode() == IrOpcode::kStart ||
|
||||
input->opcode() == IrOpcode::kDead ||
|
||||
input->opcode() == IrOpcode::kDeadValue);
|
||||
input->opcode() == IrOpcode::kDead);
|
||||
}
|
||||
// Effect inputs should be effect-producing nodes (or sentinels).
|
||||
for (int i = 0; i < node->op()->EffectInputCount(); i++) {
|
||||
@ -1890,9 +1884,7 @@ void Verifier::VerifyEdgeInputReplacement(const Edge& edge,
|
||||
DCHECK(!NodeProperties::IsEffectEdge(edge) ||
|
||||
replacement->op()->EffectOutputCount() > 0);
|
||||
DCHECK(!NodeProperties::IsFrameStateEdge(edge) ||
|
||||
replacement->opcode() == IrOpcode::kFrameState ||
|
||||
replacement->opcode() == IrOpcode::kDead ||
|
||||
replacement->opcode() == IrOpcode::kDeadValue);
|
||||
replacement->opcode() == IrOpcode::kFrameState);
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
@ -1,13 +0,0 @@
|
||||
// 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
|
||||
|
||||
function f() {
|
||||
for (var x = 10; x > 5; x -= 16) {}
|
||||
}
|
||||
f();
|
||||
f();
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
f();
|
@ -1,21 +0,0 @@
|
||||
// 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
|
||||
|
||||
'use strict';
|
||||
var a = { x:0 };
|
||||
var b = {};
|
||||
Object.defineProperty(b, "x", {get: function () {}});
|
||||
|
||||
function f(o) {
|
||||
return 5 + o.x++;
|
||||
}
|
||||
|
||||
try {
|
||||
f(a);
|
||||
f(b);
|
||||
} catch (e) {}
|
||||
%OptimizeFunctionOnNextCall(f);
|
||||
f(a);
|
@ -24,7 +24,7 @@ class DeadCodeEliminationTest : public GraphTest {
|
||||
|
||||
protected:
|
||||
Reduction Reduce(AdvancedReducer::Editor* editor, Node* node) {
|
||||
DeadCodeElimination reducer(editor, graph(), common(), zone());
|
||||
DeadCodeElimination reducer(editor, graph(), common());
|
||||
return reducer.Reduce(node);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user