Commit f010b28f authored by Mike Stanton's avatar Mike Stanton Committed by Commit Bot

[TurboFan] Diagnostic code to track down bug in representation selection

We need to characterize the types of dead (IrOpcode::kDead) nodes
introduced in compilation phases prior to representation selection.
Normally, a dead node isn't expected at the start of this phase. The
question is, which phase introduced the dead node and failed to
deal with it properly?

Bug: chromium:780658
Change-Id: Ief5b45480bb7d704a2d09dafd60b5d389e0fd42e
Reviewed-on: https://chromium-review.googlesource.com/765968Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Michael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49328}
parent 2bc09c95
...@@ -3191,7 +3191,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, ...@@ -3191,7 +3191,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
// The frame state will be inserted later. Here we misuse the {Dead} node // The frame state will be inserted later. Here we misuse the {Dead} node
// as a sentinel to be later overwritten with the real frame state by the // as a sentinel to be later overwritten with the real frame state by the
// calls to {PrepareFrameState} within individual visitor methods. // calls to {PrepareFrameState} within individual visitor methods.
*current_input++ = jsgraph()->Dead(); *current_input++ = jsgraph()->Dead(JSGraph::DeadCustomer::GraphBuilding);
} }
if (has_effect) { if (has_effect) {
*current_input++ = environment()->GetEffectDependency(); *current_input++ = environment()->GetEffectDependency();
......
...@@ -390,7 +390,9 @@ void EffectControlLinearizer::Run() { ...@@ -390,7 +390,9 @@ void EffectControlLinearizer::Run() {
// The input blocks do not have the same effect. We have // The input blocks do not have the same effect. We have
// to create an effect phi node. // to create an effect phi node.
inputs_buffer.clear(); inputs_buffer.clear();
inputs_buffer.resize(block->PredecessorCount(), jsgraph()->Dead()); inputs_buffer.resize(
block->PredecessorCount(),
jsgraph()->Dead(JSGraph::DeadCustomer::Unspecified));
inputs_buffer.push_back(control); inputs_buffer.push_back(control);
effect = graph()->NewNode( effect = graph()->NewNode(
common()->EffectPhi(static_cast<int>(block->PredecessorCount())), common()->EffectPhi(static_cast<int>(block->PredecessorCount())),
......
...@@ -74,7 +74,7 @@ Reduction EscapeAnalysisReducer::Reduce(Node* node) { ...@@ -74,7 +74,7 @@ Reduction EscapeAnalysisReducer::Reduce(Node* node) {
DCHECK(node->opcode() != IrOpcode::kAllocate && DCHECK(node->opcode() != IrOpcode::kAllocate &&
node->opcode() != IrOpcode::kFinishRegion); node->opcode() != IrOpcode::kFinishRegion);
DCHECK_NE(replacement, node); DCHECK_NE(replacement, node);
if (replacement != jsgraph()->Dead()) { if (replacement != jsgraph()->Dead(JSGraph::DeadCustomer::EscapeAnalysis)) {
replacement = MaybeGuard(node, replacement); replacement = MaybeGuard(node, replacement);
} }
RelaxEffectsAndControls(node); RelaxEffectsAndControls(node);
...@@ -178,7 +178,7 @@ Node* EscapeAnalysisReducer::ReduceDeoptState(Node* node, Node* effect, ...@@ -178,7 +178,7 @@ Node* EscapeAnalysisReducer::ReduceDeoptState(Node* node, Node* effect,
Node* field = Node* field =
analysis_result().GetVirtualObjectField(vobject, offset, effect); analysis_result().GetVirtualObjectField(vobject, offset, effect);
CHECK_NOT_NULL(field); CHECK_NOT_NULL(field);
if (field != jsgraph()->Dead()) { if (field != jsgraph()->Dead(JSGraph::DeadCustomer::EscapeAnalysis)) {
inputs.push_back(ReduceDeoptState(field, effect, deduplicator)); inputs.push_back(ReduceDeoptState(field, effect, deduplicator));
} }
} }
......
...@@ -216,7 +216,10 @@ class EscapeAnalysisTracker : public ZoneObject { ...@@ -216,7 +216,10 @@ class EscapeAnalysisTracker : public ZoneObject {
replacement->id()); replacement->id());
} }
void MarkForDeletion() { SetReplacement(tracker_->jsgraph_->Dead()); } void MarkForDeletion() {
SetReplacement(
tracker_->jsgraph_->Dead(JSGraph::DeadCustomer::EscapeAnalysis));
}
~Scope() { ~Scope() {
if (replacement_ != tracker_->replacements_[current_node()] || if (replacement_ != tracker_->replacements_[current_node()] ||
...@@ -430,7 +433,10 @@ VariableTracker::State VariableTracker::MergeInputs(Node* effect_phi) { ...@@ -430,7 +433,10 @@ VariableTracker::State VariableTracker::MergeInputs(Node* effect_phi) {
// must have been created by a previous reduction of this [effect_phi]. // must have been created by a previous reduction of this [effect_phi].
for (int i = 0; i < arity; ++i) { for (int i = 0; i < arity; ++i) {
NodeProperties::ReplaceValueInput( NodeProperties::ReplaceValueInput(
old_value, buffer_[i] ? buffer_[i] : graph_->Dead(), i); old_value,
buffer_[i] ? buffer_[i]
: graph_->Dead(JSGraph::DeadCustomer::EscapeAnalysis),
i);
// This change cannot affect the rest of the reducer, so there is no // This change cannot affect the rest of the reducer, so there is no
// need to trigger additional revisitations. // need to trigger additional revisitations.
} }
...@@ -540,7 +546,8 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current, ...@@ -540,7 +546,8 @@ void ReduceNode(const Operator* op, EscapeAnalysisTracker::Scope* current,
if (const VirtualObject* vobject = current->InitVirtualObject(size_int)) { if (const VirtualObject* vobject = current->InitVirtualObject(size_int)) {
// Initialize with dead nodes as a sentinel for uninitialized memory. // Initialize with dead nodes as a sentinel for uninitialized memory.
for (Variable field : *vobject) { for (Variable field : *vobject) {
current->Set(field, jsgraph->Dead()); current->Set(field,
jsgraph->Dead(JSGraph::DeadCustomer::EscapeAnalysis));
} }
} }
break; break;
......
...@@ -301,10 +301,30 @@ Node* JSGraph::SingleDeadTypedStateValues() { ...@@ -301,10 +301,30 @@ Node* JSGraph::SingleDeadTypedStateValues() {
SparseInputMask(SparseInputMask::kEndMarker << 1)))); SparseInputMask(SparseInputMask::kEndMarker << 1))));
} }
Node* JSGraph::Dead() { Node* JSGraph::Dead(DeadCustomer which) {
return CACHED(kDead, graph()->NewNode(common()->Dead())); switch (which) {
#define RETURN_CUSTOMER_NODE(customer) \
case customer: \
return CACHED(kDead##customer, graph()->NewNode(common()->Dead()));
CUSTOMER_LIST(RETURN_CUSTOMER_NODE)
#undef RETURN_CUSTOMER_NODE
default:
V8_Fatal(__FILE__, __LINE__, "Unexpected Which dead node detected");
}
return nullptr;
} }
const char* JSGraph::WhichDeadNode(Node* node) {
#define SEARCH_FOR_DEAD_CUSTOMER(name) \
if (node == cached_nodes_[kDead##name]) { \
return #name; \
}
CUSTOMER_LIST(SEARCH_FOR_DEAD_CUSTOMER)
#undef SEARCH_FOR_DEAD_CUSTOMER
return "Uncached dead node";
}
void JSGraph::GetCachedNodes(NodeVector* nodes) { void JSGraph::GetCachedNodes(NodeVector* nodes) {
cache_.GetCachedNodes(nodes); cache_.GetCachedNodes(nodes);
...@@ -315,6 +335,8 @@ void JSGraph::GetCachedNodes(NodeVector* nodes) { ...@@ -315,6 +335,8 @@ void JSGraph::GetCachedNodes(NodeVector* nodes) {
} }
} }
#undef CACHED
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -152,8 +152,26 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -152,8 +152,26 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
// dead accumulator. // dead accumulator.
Node* SingleDeadTypedStateValues(); Node* SingleDeadTypedStateValues();
// Create a control node that serves as dependency for dead nodes. // Create a control node that serves as dependency for dead nodes.
Node* Dead(); // TODO(mvstanton): We distinguish between different types of dead nodes
// to track down bug chromium:780658. After fixing this bug, the
// enum can be removed.
#define CUSTOMER_LIST(V) \
V(GraphBuilding) \
V(TypeHint) \
V(Inlining) \
V(ContextSpecialization) \
V(EscapeAnalysis) \
V(GraphReducer) \
V(Unspecified)
enum DeadCustomer {
#define DEFINE_DEAD_CUSTOMER_ENUM(name) name,
CUSTOMER_LIST(DEFINE_DEAD_CUSTOMER_ENUM)
#undef DEFINE_DEAD_CUSTOMER_ENUM
};
Node* Dead(DeadCustomer which);
const char* WhichDeadNode(Node* node);
CommonOperatorBuilder* common() const { return common_; } CommonOperatorBuilder* common() const { return common_; }
JSOperatorBuilder* javascript() const { return javascript_; } JSOperatorBuilder* javascript() const { return javascript_; }
...@@ -195,8 +213,10 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) { ...@@ -195,8 +213,10 @@ class V8_EXPORT_PRIVATE JSGraph : public NON_EXPORTED_BASE(ZoneObject) {
kNaNConstant, kNaNConstant,
kEmptyStateValues, kEmptyStateValues,
kSingleDeadTypedStateValues, kSingleDeadTypedStateValues,
kDead, #define DEFINE_CACHED_DEAD_CUSTOMER_ENUM(name) kDead##name,
kNumCachedNodes // Must remain last. CUSTOMER_LIST(DEFINE_CACHED_DEAD_CUSTOMER_ENUM)
#undef DEFINE_CACHED_DEAD_CUSTOMER_ENUM
kNumCachedNodes // Must remain last.
}; };
Isolate* isolate_; Isolate* isolate_;
......
...@@ -540,11 +540,15 @@ bool JSInliningHeuristic::TryReuseDispatch(Node* node, Node* callee, ...@@ -540,11 +540,15 @@ bool JSInliningHeuristic::TryReuseDispatch(Node* node, Node* callee,
} }
// Mark the control inputs dead, so that we can kill the merge. // Mark the control inputs dead, so that we can kill the merge.
node->ReplaceInput(input_count - 1, jsgraph()->Dead()); node->ReplaceInput(input_count - 1,
callee->ReplaceInput(num_calls, jsgraph()->Dead()); jsgraph()->Dead(JSGraph::DeadCustomer::Inlining));
effect_phi->ReplaceInput(num_calls, jsgraph()->Dead()); callee->ReplaceInput(num_calls,
jsgraph()->Dead(JSGraph::DeadCustomer::Inlining));
effect_phi->ReplaceInput(num_calls,
jsgraph()->Dead(JSGraph::DeadCustomer::Inlining));
if (checkpoint) { if (checkpoint) {
checkpoint->ReplaceInput(2, jsgraph()->Dead()); checkpoint->ReplaceInput(2,
jsgraph()->Dead(JSGraph::DeadCustomer::Inlining));
} }
merge->Kill(); merge->Kill();
......
...@@ -179,7 +179,7 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, ...@@ -179,7 +179,7 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
control_output); control_output);
} else { } else {
ReplaceWithValue(exception_target, exception_target, exception_target, ReplaceWithValue(exception_target, exception_target, exception_target,
jsgraph()->Dead()); jsgraph()->Dead(JSGraph::DeadCustomer::Inlining));
} }
} }
...@@ -224,8 +224,9 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context, ...@@ -224,8 +224,9 @@ Reduction JSInliner::InlineCall(Node* call, Node* new_target, Node* context,
ReplaceWithValue(call, value_output, effect_output, control_output); ReplaceWithValue(call, value_output, effect_output, control_output);
return Changed(value_output); return Changed(value_output);
} else { } else {
ReplaceWithValue(call, jsgraph()->Dead(), jsgraph()->Dead(), ReplaceWithValue(call, jsgraph()->Dead(JSGraph::DeadCustomer::Inlining),
jsgraph()->Dead()); jsgraph()->Dead(JSGraph::DeadCustomer::Inlining),
jsgraph()->Dead(JSGraph::DeadCustomer::Inlining));
return Changed(call); return Changed(call);
} }
} }
......
...@@ -890,7 +890,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess( ...@@ -890,7 +890,8 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
// Generate the final merge point for all (polymorphic) branches. // Generate the final merge point for all (polymorphic) branches.
int const control_count = static_cast<int>(controls.size()); int const control_count = static_cast<int>(controls.size());
if (control_count == 0) { if (control_count == 0) {
value = effect = control = jsgraph()->Dead(); value = effect = control =
jsgraph()->Dead(JSGraph::DeadCustomer::ContextSpecialization);
} else if (control_count == 1) { } else if (control_count == 1) {
value = values.front(); value = values.front();
effect = effects.front(); effect = effects.front();
...@@ -976,7 +977,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { ...@@ -976,7 +977,8 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
NamedAccess const& p = NamedAccessOf(node->op()); NamedAccess const& p = NamedAccessOf(node->op());
Node* const receiver = NodeProperties::GetValueInput(node, 0); Node* const receiver = NodeProperties::GetValueInput(node, 0);
Node* const value = jsgraph()->Dead(); Node* const value =
jsgraph()->Dead(JSGraph::DeadCustomer::ContextSpecialization);
// Check if we have a constant receiver. // Check if we have a constant receiver.
HeapObjectMatcher m(receiver); HeapObjectMatcher m(receiver);
...@@ -1243,7 +1245,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess( ...@@ -1243,7 +1245,8 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
// Generate the final merge point for all (polymorphic) branches. // Generate the final merge point for all (polymorphic) branches.
int const control_count = static_cast<int>(controls.size()); int const control_count = static_cast<int>(controls.size());
if (control_count == 0) { if (control_count == 0) {
value = effect = control = jsgraph()->Dead(); value = effect = control =
jsgraph()->Dead(JSGraph::DeadCustomer::ContextSpecialization);
} else if (control_count == 1) { } else if (control_count == 1) {
value = values.front(); value = values.front();
effect = effects.front(); effect = effects.front();
...@@ -1442,7 +1445,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) { ...@@ -1442,7 +1445,7 @@ Reduction JSNativeContextSpecialization::ReduceJSLoadProperty(Node* node) {
PropertyAccess const& p = PropertyAccessOf(node->op()); PropertyAccess const& p = PropertyAccessOf(node->op());
Node* receiver = NodeProperties::GetValueInput(node, 0); Node* receiver = NodeProperties::GetValueInput(node, 0);
Node* name = NodeProperties::GetValueInput(node, 1); Node* name = NodeProperties::GetValueInput(node, 1);
Node* value = jsgraph()->Dead(); Node* value = jsgraph()->Dead(JSGraph::DeadCustomer::ContextSpecialization);
Node* effect = NodeProperties::GetEffectInput(node); Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node); Node* control = NodeProperties::GetControlInput(node);
......
...@@ -428,7 +428,7 @@ Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect, ...@@ -428,7 +428,7 @@ Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) { if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
Node* deoptimize = jsgraph()->graph()->NewNode( Node* deoptimize = jsgraph()->graph()->NewNode(
jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason), jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason),
jsgraph()->Dead(), effect, control); jsgraph()->Dead(JSGraph::DeadCustomer::TypeHint), effect, control);
Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize); Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
deoptimize->ReplaceInput(0, frame_state); deoptimize->ReplaceInput(0, frame_state);
return deoptimize; return deoptimize;
......
...@@ -664,7 +664,8 @@ class SourcePositionWrapper final : public Reducer { ...@@ -664,7 +664,8 @@ class SourcePositionWrapper final : public Reducer {
class JSGraphReducer final : public GraphReducer { class JSGraphReducer final : public GraphReducer {
public: public:
JSGraphReducer(JSGraph* jsgraph, Zone* zone) JSGraphReducer(JSGraph* jsgraph, Zone* zone)
: GraphReducer(zone, jsgraph->graph(), jsgraph->Dead()) {} : GraphReducer(zone, jsgraph->graph(),
jsgraph->Dead(JSGraph::DeadCustomer::GraphReducer)) {}
~JSGraphReducer() final {} ~JSGraphReducer() final {}
}; };
......
...@@ -206,6 +206,16 @@ class InputUseInfos { ...@@ -206,6 +206,16 @@ class InputUseInfos {
#endif // DEBUG #endif // DEBUG
// TODO(mvstanton): Remove after fixing chromium:780658.
static void UnexpectedDeadOpcode(const char* file, int line,
const char* deadCode, Node* node) {
// Record the deadcode in the stack to ease minidump debugging.
const char* format_string = "Unexpected dead opcode %s, node #%i\n.";
char buffer[256];
snprintf(buffer, sizeof(buffer), format_string, deadCode, node->id());
V8_Fatal(file, line, format_string, deadCode, node->id());
}
bool CanOverflowSigned32(const Operator* op, Type* left, Type* right, bool CanOverflowSigned32(const Operator* op, Type* left, Type* right,
Zone* type_zone) { Zone* type_zone) {
// We assume the inputs are checked Signed32 (or known statically // We assume the inputs are checked Signed32 (or known statically
...@@ -3047,6 +3057,11 @@ class RepresentationSelector { ...@@ -3047,6 +3057,11 @@ class RepresentationSelector {
// Assume the output is tagged. // Assume the output is tagged.
return SetOutput(node, MachineRepresentation::kTagged); return SetOutput(node, MachineRepresentation::kTagged);
case IrOpcode::kDead: {
const char* deadVersion = jsgraph_->WhichDeadNode(node);
UnexpectedDeadOpcode(__FILE__, __LINE__, deadVersion, node);
break;
}
default: default:
V8_Fatal( V8_Fatal(
__FILE__, __LINE__, __FILE__, __LINE__,
...@@ -3092,7 +3107,7 @@ class RepresentationSelector { ...@@ -3092,7 +3107,7 @@ class RepresentationSelector {
DCHECK_EQ(0, node->op()->EffectOutputCount()); DCHECK_EQ(0, node->op()->EffectOutputCount());
} }
node->ReplaceUses(jsgraph_->Dead()); node->ReplaceUses(jsgraph_->Dead(JSGraph::DeadCustomer::Unspecified));
node->NullAllInputs(); // The {node} is now dead. node->NullAllInputs(); // The {node} is now dead.
} }
......
...@@ -94,7 +94,9 @@ WasmGraphBuilder::WasmGraphBuilder( ...@@ -94,7 +94,9 @@ WasmGraphBuilder::WasmGraphBuilder(
DCHECK_NOT_NULL(jsgraph_); DCHECK_NOT_NULL(jsgraph_);
} }
Node* WasmGraphBuilder::Error() { return jsgraph()->Dead(); } Node* WasmGraphBuilder::Error() {
return jsgraph()->Dead(JSGraph::DeadCustomer::Unspecified);
}
Node* WasmGraphBuilder::Start(unsigned params) { Node* WasmGraphBuilder::Start(unsigned params) {
Node* start = graph()->NewNode(jsgraph()->common()->Start(params)); Node* start = graph()->NewNode(jsgraph()->common()->Start(params));
......
...@@ -27,7 +27,8 @@ class BranchEliminationTest : public GraphTest { ...@@ -27,7 +27,8 @@ class BranchEliminationTest : public GraphTest {
JSOperatorBuilder javascript(zone()); JSOperatorBuilder javascript(zone());
JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr, JSGraph jsgraph(isolate(), graph(), common(), &javascript, nullptr,
machine()); machine());
GraphReducer graph_reducer(zone(), graph(), jsgraph.Dead()); GraphReducer graph_reducer(
zone(), graph(), jsgraph.Dead(JSGraph::DeadCustomer::Unspecified));
BranchElimination branch_condition_elimination(&graph_reducer, &jsgraph, BranchElimination branch_condition_elimination(&graph_reducer, &jsgraph,
zone()); zone());
graph_reducer.AddReducer(&branch_condition_elimination); graph_reducer.AddReducer(&branch_condition_elimination);
......
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