[turbofan] Added --csa-trap-on-node option that helps debugging graph verification issues.
The error reported by the graph verifier looks like: # # Fatal error in ../src/compiler/machine-graph-verifier.cc, line 638 # TypeError: node #54:ChangeInt32ToInt64 uses node #53:ChangeUint32ToUint64 which doesn't have an int32-compatible representation. # # Specify option --csa-trap-on-node=test,54 for debugging. # BUG= Review-Url: https://codereview.chromium.org/2574353002 Cr-Commit-Position: refs/heads/master@{#41721}
This commit is contained in:
parent
7bd61b601c
commit
1805315470
@ -11,6 +11,38 @@ namespace internal {
|
||||
|
||||
using compiler::Node;
|
||||
|
||||
CodeStubAssembler::CodeStubAssembler(compiler::CodeAssemblerState* state)
|
||||
: compiler::CodeAssembler(state) {
|
||||
if (DEBUG_BOOL && FLAG_csa_trap_on_node != nullptr) {
|
||||
HandleBreakOnNode();
|
||||
}
|
||||
}
|
||||
|
||||
void CodeStubAssembler::HandleBreakOnNode() {
|
||||
// FLAG_csa_trap_on_node should be in a form "STUB,NODE" where STUB is a
|
||||
// string specifying the name of a stub and NODE is number specifying node id.
|
||||
const char* name = state()->name();
|
||||
size_t name_length = strlen(name);
|
||||
if (strncmp(FLAG_csa_trap_on_node, name, name_length) != 0) {
|
||||
// Different name.
|
||||
return;
|
||||
}
|
||||
size_t option_length = strlen(FLAG_csa_trap_on_node);
|
||||
if (option_length < name_length + 2 ||
|
||||
FLAG_csa_trap_on_node[name_length] != ',') {
|
||||
// Option is too short.
|
||||
return;
|
||||
}
|
||||
const char* start = &FLAG_csa_trap_on_node[name_length + 1];
|
||||
char* end;
|
||||
int node_id = static_cast<int>(strtol(start, &end, 10));
|
||||
if (start == end) {
|
||||
// Bad node id.
|
||||
return;
|
||||
}
|
||||
BreakOnNode(node_id);
|
||||
}
|
||||
|
||||
void CodeStubAssembler::Assert(const NodeGenerator& codition_body,
|
||||
const char* message, const char* file,
|
||||
int line) {
|
||||
|
@ -53,8 +53,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
public:
|
||||
typedef compiler::Node Node;
|
||||
|
||||
CodeStubAssembler(compiler::CodeAssemblerState* state)
|
||||
: compiler::CodeAssembler(state) {}
|
||||
CodeStubAssembler(compiler::CodeAssemblerState* state);
|
||||
|
||||
enum AllocationFlag : uint8_t {
|
||||
kNone = 0,
|
||||
@ -1124,6 +1123,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
private:
|
||||
friend class CodeStubArguments;
|
||||
|
||||
void HandleBreakOnNode();
|
||||
|
||||
Node* AllocateRawAligned(Node* size_in_bytes, AllocationFlags flags,
|
||||
Node* top_address, Node* limit_address);
|
||||
Node* AllocateRawUnaligned(Node* size_in_bytes, AllocationFlags flags,
|
||||
|
@ -65,6 +65,28 @@ CodeAssemblerState::~CodeAssemblerState() {}
|
||||
|
||||
CodeAssembler::~CodeAssembler() {}
|
||||
|
||||
class BreakOnNodeDecorator final : public GraphDecorator {
|
||||
public:
|
||||
explicit BreakOnNodeDecorator(NodeId node_id) : node_id_(node_id) {}
|
||||
|
||||
void Decorate(Node* node) final {
|
||||
if (node->id() == node_id_) {
|
||||
base::OS::DebugBreak();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
NodeId node_id_;
|
||||
};
|
||||
|
||||
void CodeAssembler::BreakOnNode(int node_id) {
|
||||
Graph* graph = raw_assembler()->graph();
|
||||
Zone* zone = graph->zone();
|
||||
GraphDecorator* decorator =
|
||||
new (zone) BreakOnNodeDecorator(static_cast<NodeId>(node_id));
|
||||
graph->AddDecorator(decorator);
|
||||
}
|
||||
|
||||
void CodeAssembler::CallPrologue() {}
|
||||
|
||||
void CodeAssembler::CallEpilogue() {}
|
||||
|
@ -454,6 +454,8 @@ class V8_EXPORT_PRIVATE CodeAssembler {
|
||||
|
||||
CodeAssemblerState* state() { return state_; }
|
||||
|
||||
void BreakOnNode(int node_id);
|
||||
|
||||
protected:
|
||||
// Enables subclasses to perform operations before and after a call.
|
||||
virtual void CallPrologue();
|
||||
@ -463,6 +465,8 @@ class V8_EXPORT_PRIVATE CodeAssembler {
|
||||
Node* CallN(CallDescriptor* descriptor, Node* code_target, Node** args);
|
||||
Node* TailCallN(CallDescriptor* descriptor, Node* code_target, Node** args);
|
||||
|
||||
void InstallBreakOnNodeDecorator();
|
||||
|
||||
RawMachineAssembler* raw_assembler() const;
|
||||
|
||||
CodeAssemblerState* state_;
|
||||
@ -545,6 +549,8 @@ class V8_EXPORT_PRIVATE CodeAssemblerState {
|
||||
|
||||
~CodeAssemblerState();
|
||||
|
||||
const char* name() const { return name_; }
|
||||
|
||||
private:
|
||||
friend class CodeAssembler;
|
||||
friend class CodeAssemblerLabel;
|
||||
|
@ -275,8 +275,12 @@ class MachineRepresentationChecker {
|
||||
public:
|
||||
MachineRepresentationChecker(
|
||||
Schedule const* const schedule,
|
||||
MachineRepresentationInferrer const* const inferrer, bool is_stub)
|
||||
: schedule_(schedule), inferrer_(inferrer), is_stub_(is_stub) {}
|
||||
MachineRepresentationInferrer const* const inferrer, bool is_stub,
|
||||
const char* name)
|
||||
: schedule_(schedule),
|
||||
inferrer_(inferrer),
|
||||
is_stub_(is_stub),
|
||||
name_(name) {}
|
||||
|
||||
void Run() {
|
||||
BasicBlockVector const* blocks = schedule_->all_blocks();
|
||||
@ -520,6 +524,7 @@ class MachineRepresentationChecker {
|
||||
std::stringstream str;
|
||||
str << "Node #" << node->id() << ":" << *node->op()
|
||||
<< " in the machine graph is not being checked.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
break;
|
||||
@ -549,6 +554,7 @@ class MachineRepresentationChecker {
|
||||
<< " uses node #" << input->id() << ":" << *input->op() << ":"
|
||||
<< input_representation << " which doesn't have a " << representation
|
||||
<< " representation.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
}
|
||||
@ -567,6 +573,7 @@ class MachineRepresentationChecker {
|
||||
str << "TypeError: node #" << node->id() << ":" << *node->op()
|
||||
<< " uses node #" << input->id() << ":" << *input->op()
|
||||
<< " which doesn't have a tagged representation.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
|
||||
@ -599,6 +606,7 @@ class MachineRepresentationChecker {
|
||||
str << "TypeError: node #" << node->id() << ":" << *node->op()
|
||||
<< " uses node #" << input->id() << ":" << *input->op()
|
||||
<< " which doesn't have a tagged or pointer representation.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
}
|
||||
@ -615,6 +623,7 @@ class MachineRepresentationChecker {
|
||||
std::ostringstream str;
|
||||
str << "TypeError: node #" << input->id() << ":" << *input->op()
|
||||
<< " is untyped.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
break;
|
||||
}
|
||||
@ -625,6 +634,7 @@ class MachineRepresentationChecker {
|
||||
str << "TypeError: node #" << node->id() << ":" << *node->op()
|
||||
<< " uses node #" << input->id() << ":" << *input->op()
|
||||
<< " which doesn't have an int32-compatible representation.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
|
||||
@ -639,6 +649,7 @@ class MachineRepresentationChecker {
|
||||
std::ostringstream str;
|
||||
str << "TypeError: node #" << input->id() << ":" << *input->op()
|
||||
<< " is untyped.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
break;
|
||||
}
|
||||
@ -651,6 +662,7 @@ class MachineRepresentationChecker {
|
||||
<< " uses node #" << input->id() << ":" << *input->op() << ":"
|
||||
<< input_representation
|
||||
<< " which doesn't have a kWord64 representation.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
|
||||
@ -664,6 +676,7 @@ class MachineRepresentationChecker {
|
||||
str << "TypeError: node #" << node->id() << ":" << *node->op()
|
||||
<< " uses node #" << input->id() << ":" << *input->op()
|
||||
<< " which doesn't have a kFloat32 representation.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
|
||||
@ -677,6 +690,7 @@ class MachineRepresentationChecker {
|
||||
str << "TypeError: node #" << node->id() << ":" << *node->op()
|
||||
<< " uses node #" << input->id() << ":" << *input->op()
|
||||
<< " which doesn't have a kFloat64 representation.";
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
|
||||
@ -703,6 +717,7 @@ class MachineRepresentationChecker {
|
||||
}
|
||||
}
|
||||
if (should_log_error) {
|
||||
PrintDebugHelp(str, node);
|
||||
FATAL(str.str().c_str());
|
||||
}
|
||||
}
|
||||
@ -765,20 +780,28 @@ class MachineRepresentationChecker {
|
||||
return false;
|
||||
}
|
||||
|
||||
void PrintDebugHelp(std::ostream& out, Node const* node) {
|
||||
if (DEBUG_BOOL) {
|
||||
out << "\n#\n# Specify option --csa-trap-on-node=" << name_ << ","
|
||||
<< node->id() << " for debugging.";
|
||||
}
|
||||
}
|
||||
|
||||
Schedule const* const schedule_;
|
||||
MachineRepresentationInferrer const* const inferrer_;
|
||||
bool is_stub_;
|
||||
const char* name_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void MachineGraphVerifier::Run(Graph* graph, Schedule const* const schedule,
|
||||
Linkage* linkage, bool is_stub,
|
||||
Linkage* linkage, bool is_stub, const char* name,
|
||||
Zone* temp_zone) {
|
||||
MachineRepresentationInferrer representation_inferrer(schedule, graph,
|
||||
linkage, temp_zone);
|
||||
MachineRepresentationChecker checker(schedule, &representation_inferrer,
|
||||
is_stub);
|
||||
is_stub, name);
|
||||
checker.Run();
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,8 @@ class Schedule;
|
||||
class MachineGraphVerifier {
|
||||
public:
|
||||
static void Run(Graph* graph, Schedule const* const schedule,
|
||||
Linkage* linkage, bool is_stub, Zone* temp_zone);
|
||||
Linkage* linkage, bool is_stub, const char* name,
|
||||
Zone* temp_zone);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
|
@ -302,7 +302,7 @@ class PipelineData {
|
||||
DCHECK(register_allocation_data_ == nullptr);
|
||||
register_allocation_data_ = new (register_allocation_zone())
|
||||
RegisterAllocationData(config, register_allocation_zone(), frame(),
|
||||
sequence(), debug_name_.get());
|
||||
sequence(), debug_name());
|
||||
}
|
||||
|
||||
void BeginPhaseKind(const char* phase_kind_name) {
|
||||
@ -317,6 +317,8 @@ class PipelineData {
|
||||
}
|
||||
}
|
||||
|
||||
const char* debug_name() const { return debug_name_.get(); }
|
||||
|
||||
private:
|
||||
Isolate* const isolate_;
|
||||
CompilationInfo* const info_;
|
||||
@ -1757,28 +1759,27 @@ bool PipelineImpl::ScheduleAndSelectInstructions(Linkage* linkage,
|
||||
}
|
||||
|
||||
bool verify_stub_graph = data->verify_graph();
|
||||
if (verify_stub_graph || (FLAG_turbo_verify_machine_graph != nullptr &&
|
||||
if (verify_stub_graph ||
|
||||
(FLAG_turbo_verify_machine_graph != nullptr &&
|
||||
(!strcmp(FLAG_turbo_verify_machine_graph, "*") ||
|
||||
!strcmp(FLAG_turbo_verify_machine_graph,
|
||||
data->info()->GetDebugName().get())))) {
|
||||
!strcmp(FLAG_turbo_verify_machine_graph, data->debug_name())))) {
|
||||
if (FLAG_trace_csa_verify) {
|
||||
AllowHandleDereference allow_deref;
|
||||
CompilationInfo* info = data->info();
|
||||
CodeTracer::Scope tracing_scope(info->isolate()->GetCodeTracer());
|
||||
OFStream os(tracing_scope.file());
|
||||
os << "--------------------------------------------------\n"
|
||||
<< "--- Verifying " << info->GetDebugName().get()
|
||||
<< " generated by TurboFan\n"
|
||||
<< "--- Verifying " << data->debug_name() << " generated by TurboFan\n"
|
||||
<< "--------------------------------------------------\n"
|
||||
<< *data->schedule()
|
||||
<< "--------------------------------------------------\n"
|
||||
<< "--- End of " << info->GetDebugName().get()
|
||||
<< " generated by TurboFan\n"
|
||||
<< "--- End of " << data->debug_name() << " generated by TurboFan\n"
|
||||
<< "--------------------------------------------------\n";
|
||||
}
|
||||
Zone temp_zone(data->isolate()->allocator(), ZONE_NAME);
|
||||
MachineGraphVerifier::Run(data->graph(), data->schedule(), linkage,
|
||||
data->info()->IsStub(), &temp_zone);
|
||||
data->info()->IsStub(), data->debug_name(),
|
||||
&temp_zone);
|
||||
}
|
||||
|
||||
data->InitializeInstructionSequence(call_descriptor);
|
||||
|
@ -444,6 +444,9 @@ DEFINE_STRING(turbo_verify_machine_graph, nullptr,
|
||||
DEFINE_BOOL(csa_verify, DEBUG_BOOL,
|
||||
"verify TurboFan machine graph of code stubs")
|
||||
DEFINE_BOOL(trace_csa_verify, false, "trace code stubs verification")
|
||||
DEFINE_STRING(csa_trap_on_node, nullptr,
|
||||
"trigger break point when a node with given id is created in "
|
||||
"given stub. The format is: StubName,NodeId")
|
||||
DEFINE_BOOL(turbo_stats, false, "print TurboFan statistics")
|
||||
DEFINE_BOOL(turbo_stats_nvp, false,
|
||||
"print TurboFan statistics in machine-readable format")
|
||||
|
Loading…
Reference in New Issue
Block a user