Commit 91386f0b authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Generate source position information

Annotate call nodes in the TF graph with source code information in the form
of byte offset relative to the wasm function start. The backend finally outputs those positions as RelocInfo.

R=bmeurer@chromium.org, mstarzinger@chromium.org, titzer@chromium.org

Review URL: https://codereview.chromium.org/1890803002

Cr-Commit-Position: refs/heads/master@{#35793}
parent ef49c6b1
......@@ -83,30 +83,15 @@ class PipelineData : public ZoneObject {
outer_zone_(info_->zone()),
zone_pool_(zone_pool),
pipeline_statistics_(pipeline_statistics),
compilation_failed_(false),
code_(Handle<Code>::null()),
profiler_data_(nullptr),
graph_zone_scope_(zone_pool_),
graph_zone_(graph_zone_scope_.zone()),
graph_(nullptr),
loop_assignment_(nullptr),
simplified_(nullptr),
machine_(nullptr),
common_(nullptr),
javascript_(nullptr),
jsgraph_(nullptr),
schedule_(nullptr),
instruction_zone_scope_(zone_pool_),
instruction_zone_(instruction_zone_scope_.zone()),
sequence_(nullptr),
frame_(nullptr),
register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()),
register_allocation_data_(nullptr) {
register_allocation_zone_(register_allocation_zone_scope_.zone()) {
PhaseScope scope(pipeline_statistics, "init pipeline data");
graph_ = new (graph_zone_) Graph(graph_zone_);
source_positions_ = new (graph_zone_->New(sizeof(SourcePositionTable)))
SourcePositionTable(graph_);
source_positions_ = new (graph_zone_) SourcePositionTable(graph_);
simplified_ = new (graph_zone_) SimplifiedOperatorBuilder(graph_zone_);
machine_ = new (graph_zone_) MachineOperatorBuilder(
graph_zone_, MachineType::PointerRepresentation(),
......@@ -117,65 +102,47 @@ class PipelineData : public ZoneObject {
JSGraph(isolate_, graph_, common_, javascript_, simplified_, machine_);
}
// For WASM compile entry point.
PipelineData(ZonePool* zone_pool, CompilationInfo* info, Graph* graph,
SourcePositionTable* source_positions)
: isolate_(info->isolate()),
info_(info),
zone_pool_(zone_pool),
graph_zone_scope_(zone_pool_),
graph_(graph),
source_positions_(source_positions),
instruction_zone_scope_(zone_pool_),
instruction_zone_(instruction_zone_scope_.zone()),
register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()) {}
// For machine graph testing entry point.
PipelineData(ZonePool* zone_pool, CompilationInfo* info, Graph* graph,
Schedule* schedule)
: isolate_(info->isolate()),
info_(info),
outer_zone_(nullptr),
zone_pool_(zone_pool),
pipeline_statistics_(nullptr),
compilation_failed_(false),
code_(Handle<Code>::null()),
profiler_data_(nullptr),
graph_zone_scope_(zone_pool_),
graph_zone_(nullptr),
graph_(graph),
source_positions_(new (info->zone()->New(sizeof(SourcePositionTable)))
SourcePositionTable(graph_)),
loop_assignment_(nullptr),
simplified_(nullptr),
machine_(nullptr),
common_(nullptr),
javascript_(nullptr),
jsgraph_(nullptr),
source_positions_(new (info->zone()) SourcePositionTable(graph_)),
schedule_(schedule),
instruction_zone_scope_(zone_pool_),
instruction_zone_(instruction_zone_scope_.zone()),
sequence_(nullptr),
frame_(nullptr),
register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()),
register_allocation_data_(nullptr) {}
register_allocation_zone_(register_allocation_zone_scope_.zone()) {}
// For register allocation testing entry point.
PipelineData(ZonePool* zone_pool, CompilationInfo* info,
InstructionSequence* sequence)
: isolate_(info->isolate()),
info_(info),
outer_zone_(nullptr),
zone_pool_(zone_pool),
pipeline_statistics_(nullptr),
compilation_failed_(false),
code_(Handle<Code>::null()),
profiler_data_(nullptr),
graph_zone_scope_(zone_pool_),
graph_zone_(nullptr),
graph_(nullptr),
loop_assignment_(nullptr),
simplified_(nullptr),
machine_(nullptr),
common_(nullptr),
javascript_(nullptr),
jsgraph_(nullptr),
schedule_(nullptr),
instruction_zone_scope_(zone_pool_),
instruction_zone_(sequence->zone()),
sequence_(sequence),
frame_(nullptr),
register_allocation_zone_scope_(zone_pool_),
register_allocation_zone_(register_allocation_zone_scope_.zone()),
register_allocation_data_(nullptr) {}
register_allocation_zone_(register_allocation_zone_scope_.zone()) {}
void Destroy() {
DeleteRegisterAllocationZone();
......@@ -208,7 +175,10 @@ class PipelineData : public ZoneObject {
Zone* graph_zone() const { return graph_zone_; }
Graph* graph() const { return graph_; }
SourcePositionTable* source_positions() const { return source_positions_; }
SourcePositionTable* source_positions() const {
DCHECK_NOT_NULL(source_positions_);
return source_positions_;
}
MachineOperatorBuilder* machine() const { return machine_; }
CommonOperatorBuilder* common() const { return common_; }
JSOperatorBuilder* javascript() const { return javascript_; }
......@@ -315,28 +285,28 @@ class PipelineData : public ZoneObject {
private:
Isolate* isolate_;
CompilationInfo* info_;
Zone* outer_zone_;
Zone* outer_zone_ = nullptr;
ZonePool* const zone_pool_;
PipelineStatistics* pipeline_statistics_;
bool compilation_failed_;
PipelineStatistics* pipeline_statistics_ = nullptr;
bool compilation_failed_ = false;
Handle<Code> code_;
BasicBlockProfiler::Data* profiler_data_;
BasicBlockProfiler::Data* profiler_data_ = nullptr;
std::ostringstream source_position_output_;
// All objects in the following group of fields are allocated in graph_zone_.
// They are all set to nullptr when the graph_zone_ is destroyed.
ZonePool::Scope graph_zone_scope_;
Zone* graph_zone_;
Graph* graph_;
SourcePositionTable* source_positions_;
LoopAssignmentAnalysis* loop_assignment_;
Zone* graph_zone_ = nullptr;
Graph* graph_ = nullptr;
SourcePositionTable* source_positions_ = nullptr;
LoopAssignmentAnalysis* loop_assignment_ = nullptr;
TypeHintAnalysis* type_hint_analysis_ = nullptr;
SimplifiedOperatorBuilder* simplified_;
MachineOperatorBuilder* machine_;
CommonOperatorBuilder* common_;
JSOperatorBuilder* javascript_;
JSGraph* jsgraph_;
Schedule* schedule_;
SimplifiedOperatorBuilder* simplified_ = nullptr;
MachineOperatorBuilder* machine_ = nullptr;
CommonOperatorBuilder* common_ = nullptr;
JSOperatorBuilder* javascript_ = nullptr;
JSGraph* jsgraph_ = nullptr;
Schedule* schedule_ = nullptr;
// All objects in the following group of fields are allocated in
// instruction_zone_. They are all set to nullptr when the instruction_zone_
......@@ -344,15 +314,15 @@ class PipelineData : public ZoneObject {
// destroyed.
ZonePool::Scope instruction_zone_scope_;
Zone* instruction_zone_;
InstructionSequence* sequence_;
Frame* frame_;
InstructionSequence* sequence_ = nullptr;
Frame* frame_ = nullptr;
// All objects in the following group of fields are allocated in
// register_allocation_zone_. They are all set to nullptr when the zone is
// destroyed.
ZonePool::Scope register_allocation_zone_scope_;
Zone* register_allocation_zone_;
RegisterAllocationData* register_allocation_data_;
RegisterAllocationData* register_allocation_data_ = nullptr;
int CalculateFixedFrameSize(CallDescriptor* descriptor) {
if (descriptor->IsJSFunctionCall()) {
......@@ -1324,7 +1294,6 @@ Handle<Code> Pipeline::GenerateCode() {
Linkage::ComputeIncoming(data.instruction_zone(), info()));
}
Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
CallDescriptor* call_descriptor,
Graph* graph, Schedule* schedule,
......@@ -1393,9 +1362,11 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
return pipeline.ScheduleAndGenerateCode(call_descriptor);
}
void Pipeline::InitializeWasmCompilation(Zone* pipeline_zone,
ZonePool* zone_pool, Graph* graph) {
data_ = new (pipeline_zone) PipelineData(zone_pool, info(), graph, nullptr);
void Pipeline::InitializeWasmCompilation(
Zone* pipeline_zone, ZonePool* zone_pool, Graph* graph,
SourcePositionTable* source_positions) {
data_ = new (pipeline_zone)
PipelineData(zone_pool, info(), graph, source_positions);
RunPrintAndVerify("Machine", true);
}
......
......@@ -25,6 +25,7 @@ class InstructionSequence;
class Linkage;
class PipelineData;
class Schedule;
class SourcePositionTable;
class ZonePool;
class Pipeline {
......@@ -64,7 +65,8 @@ class Pipeline {
static OptimizedCompileJob* NewCompilationJob(CompilationInfo* info);
void InitializeWasmCompilation(Zone* pipeline_zone, ZonePool* zone_pool,
Graph* graph);
Graph* graph,
SourcePositionTable* source_positions);
bool ExecuteWasmCompilation(CallDescriptor* descriptor);
Handle<Code> FinalizeWasmCompilation(CallDescriptor* descriptor);
......
......@@ -16,7 +16,8 @@ class SourcePositionTable::Decorator final : public GraphDecorator {
: source_positions_(source_positions) {}
void Decorate(Node* node) final {
source_positions_->table_.Set(node, source_positions_->current_position_);
source_positions_->SetSourcePosition(node,
source_positions_->current_position_);
}
private:
......@@ -49,6 +50,10 @@ SourcePosition SourcePositionTable::GetSourcePosition(Node* node) const {
return table_.Get(node);
}
void SourcePositionTable::SetSourcePosition(Node* node,
SourcePosition position) {
table_.Set(node, position);
}
void SourcePositionTable::Print(std::ostream& os) const {
os << "{";
......
......@@ -38,8 +38,7 @@ inline bool operator!=(const SourcePosition& lhs, const SourcePosition& rhs) {
return !(lhs == rhs);
}
class SourcePositionTable final {
class SourcePositionTable final : public ZoneObject {
public:
class Scope final {
public:
......@@ -71,6 +70,7 @@ class SourcePositionTable final {
void RemoveDecorator();
SourcePosition GetSourcePosition(Node* node) const;
void SetSourcePosition(Node* node, SourcePosition position);
void Print(std::ostream& os) const;
......
......@@ -245,8 +245,9 @@ class WasmTrapHelper : public ZoneObject {
}
};
WasmGraphBuilder::WasmGraphBuilder(Zone* zone, JSGraph* jsgraph,
wasm::FunctionSig* function_signature)
WasmGraphBuilder::WasmGraphBuilder(
Zone* zone, JSGraph* jsgraph, wasm::FunctionSig* function_signature,
compiler::SourcePositionTable* source_position_table)
: zone_(zone),
jsgraph_(jsgraph),
module_(nullptr),
......@@ -258,7 +259,8 @@ WasmGraphBuilder::WasmGraphBuilder(Zone* zone, JSGraph* jsgraph,
cur_buffer_(def_buffer_),
cur_bufsize_(kDefaultBufferSize),
trap_(new (zone) WasmTrapHelper(this)),
function_signature_(function_signature) {
function_signature_(function_signature),
source_position_table_(source_position_table) {
DCHECK_NOT_NULL(jsgraph_);
}
......@@ -2664,6 +2666,12 @@ void WasmGraphBuilder::Int64LoweringForTesting() {
}
}
void WasmGraphBuilder::SetSourcePosition(Node* node, int position) {
compiler::SourcePosition pos(position);
if (source_position_table_)
source_position_table_->SetSourcePosition(node, pos);
}
static void RecordFunctionCompilation(Logger::LogEventsAndTags tag,
CompilationInfo* info,
const char* message, uint32_t index,
......@@ -2756,7 +2764,7 @@ Handle<JSFunction> CompileJSToWasmWrapper(
CompilationInfo info(func_name, isolate, &zone, flags);
Handle<Code> code =
Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
Pipeline::GenerateCodeForTesting(&info, incoming, &graph);
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_opt_code && !code.is_null()) {
OFStream os(stdout);
......@@ -2847,11 +2855,10 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
return code;
}
JSGraph* BuildGraphForWasmFunction(Zone* zone, wasm::ErrorThrower& thrower,
Isolate* isolate,
wasm::ModuleEnv*& module_env,
const wasm::WasmFunction& function,
double* decode_ms) {
std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
Zone* zone, wasm::ErrorThrower& thrower, Isolate* isolate,
wasm::ModuleEnv*& module_env, const wasm::WasmFunction& function,
double* decode_ms) {
base::ElapsedTimer decode_timer;
if (FLAG_trace_wasm_decode_time) {
decode_timer.Start();
......@@ -2864,7 +2871,9 @@ JSGraph* BuildGraphForWasmFunction(Zone* zone, wasm::ErrorThrower& thrower,
InstructionSelector::SupportedMachineOperatorFlags());
JSGraph* jsgraph =
new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine);
WasmGraphBuilder builder(zone, jsgraph, function.sig);
SourcePositionTable* source_position_table =
new (zone) SourcePositionTable(graph);
WasmGraphBuilder builder(zone, jsgraph, function.sig, source_position_table);
wasm::FunctionBody body = {
module_env, function.sig, module_env->module->module_start,
module_env->module->module_start + function.code_start_offset,
......@@ -2889,7 +2898,7 @@ JSGraph* BuildGraphForWasmFunction(Zone* zone, wasm::ErrorThrower& thrower,
SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
function.func_index, name.length, name.name);
thrower.Failed(buffer.start(), result);
return nullptr;
return std::make_pair(nullptr, nullptr);
}
int index = static_cast<int>(function.func_index);
if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
......@@ -2898,7 +2907,7 @@ JSGraph* BuildGraphForWasmFunction(Zone* zone, wasm::ErrorThrower& thrower,
if (FLAG_trace_wasm_decode_time) {
*decode_ms = decode_timer.Elapsed().InMillisecondsF();
}
return jsgraph;
return std::make_pair(jsgraph, source_position_table);
}
// Helper function to compile a single function.
......@@ -2917,9 +2926,11 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
compiler::ZonePool zone_pool(isolate->allocator());
compiler::ZonePool::Scope graph_zone_scope(&zone_pool);
double decode_ms = 0;
JSGraph* jsgraph =
std::pair<JSGraph*, SourcePositionTable*> graph_result =
BuildGraphForWasmFunction(graph_zone_scope.zone(), thrower, isolate,
module_env, function, &decode_ms);
JSGraph* jsgraph = graph_result.first;
SourcePositionTable* source_positions = graph_result.second;
if (jsgraph == nullptr) {
return Handle<Code>::null();
......@@ -2958,7 +2969,7 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
compiler::ZonePool::Scope pipeline_zone_scope(&zone_pool);
Pipeline pipeline(&info);
pipeline.InitializeWasmCompilation(pipeline_zone_scope.zone(), &zone_pool,
jsgraph->graph());
jsgraph->graph(), source_positions);
Handle<Code> code;
if (pipeline.ExecuteWasmCompilation(descriptor)) {
code = pipeline.FinalizeWasmCompilation(descriptor);
......
......@@ -19,6 +19,7 @@ class Node;
class JSGraph;
class Graph;
class Operator;
class SourcePositionTable;
}
namespace wasm {
......@@ -56,7 +57,9 @@ Handle<JSFunction> CompileJSToWasmWrapper(
class WasmTrapHelper;
class WasmGraphBuilder {
public:
WasmGraphBuilder(Zone* z, JSGraph* g, wasm::FunctionSig* function_signature);
WasmGraphBuilder(
Zone* z, JSGraph* g, wasm::FunctionSig* function_signature,
compiler::SourcePositionTable* source_position_table = nullptr);
Node** Buffer(size_t count) {
if (count > cur_bufsize_) {
......@@ -140,6 +143,8 @@ class WasmGraphBuilder {
void Int64LoweringForTesting();
void SetSourcePosition(Node* node, int position);
private:
static const int kDefaultBufferSize = 16;
friend class WasmTrapHelper;
......@@ -160,6 +165,8 @@ class WasmGraphBuilder {
wasm::FunctionSig* function_signature_;
SetOncePointer<const Operator> allocate_heap_number_operator_;
compiler::SourcePositionTable* source_position_table_ = nullptr;
// Internal helper methods.
JSGraph* jsgraph() { return jsgraph_; }
Graph* graph();
......
......@@ -718,6 +718,7 @@ class SR_WasmDecoder : public WasmDecoder {
break;
}
case kExprUnreachable: {
// TODO(clemensh): add source position for unreachable
BUILD0(Unreachable);
ssa_env_->Kill(SsaEnv::kControlEnd);
Leaf(kAstEnd, nullptr);
......@@ -1235,6 +1236,7 @@ class SR_WasmDecoder : public WasmDecoder {
buffer[i] = p->tree->children[i - 1]->node;
}
p->tree->node = builder_->CallDirect(operand.index, buffer);
AddSourcePosition(p);
}
break;
}
......@@ -1253,6 +1255,7 @@ class SR_WasmDecoder : public WasmDecoder {
buffer[i] = p->tree->children[i]->node;
}
p->tree->node = builder_->CallIndirect(operand.index, buffer);
AddSourcePosition(p);
}
break;
}
......@@ -1270,6 +1273,7 @@ class SR_WasmDecoder : public WasmDecoder {
buffer[i] = p->tree->children[i - 1]->node;
}
p->tree->node = builder_->CallImport(operand.index, buffer);
AddSourcePosition(p);
}
break;
}
......@@ -1631,6 +1635,17 @@ class SR_WasmDecoder : public WasmDecoder {
}
return assigned;
}
void AddSourcePosition(Production* p) {
DCHECK_NOT_NULL(p->tree->node);
AddSourcePosition(p->tree->node, p->pc());
}
void AddSourcePosition(TFNode* node, const byte* pc) {
int offset = static_cast<int>(pc - start_);
DCHECK_EQ(pc - start_, offset); // overflows cannot happen
builder_->SetSourcePosition(node, offset);
}
};
bool DecodeLocalDecls(AstLocalDecls& decls, const byte* start,
......
......@@ -1727,14 +1727,14 @@ static void TestBuildGraphForSimpleExpression(WasmOpcode opcode) {
if (sig->parameter_count() == 1) {
byte code[] = {WASM_NO_LOCALS, static_cast<byte>(opcode), kExprGetLocal, 0};
TestBuildingGraph(&zone, &jsgraph, nullptr, sig, code,
TestBuildingGraph(&zone, &jsgraph, nullptr, sig, nullptr, code,
code + arraysize(code));
} else {
CHECK_EQ(2, sig->parameter_count());
byte code[] = {WASM_NO_LOCALS, static_cast<byte>(opcode),
kExprGetLocal, 0,
kExprGetLocal, 1};
TestBuildingGraph(&zone, &jsgraph, nullptr, sig, code,
TestBuildingGraph(&zone, &jsgraph, nullptr, sig, nullptr, code,
code + arraysize(code));
}
}
......
......@@ -17,6 +17,7 @@
#include "src/compiler/node.h"
#include "src/compiler/pipeline.h"
#include "src/compiler/wasm-compiler.h"
#include "src/compiler/zone-pool.h"
#include "src/wasm/ast-decoder.h"
#include "src/wasm/wasm-js.h"
......@@ -242,9 +243,10 @@ class TestingModule : public ModuleEnv {
};
inline void TestBuildingGraph(Zone* zone, JSGraph* jsgraph, ModuleEnv* module,
FunctionSig* sig, const byte* start,
const byte* end) {
compiler::WasmGraphBuilder builder(zone, jsgraph, sig);
FunctionSig* sig,
SourcePositionTable* source_position_table,
const byte* start, const byte* end) {
compiler::WasmGraphBuilder builder(zone, jsgraph, sig, source_position_table);
TreeResult result =
BuildTFGraph(zone->allocator(), &builder, module, sig, start, end);
if (result.failed()) {
......@@ -418,7 +420,8 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
sig(sig),
descriptor_(nullptr),
testing_module_(module),
debug_name_(debug_name) {
debug_name_(debug_name),
source_position_table_(this->graph()) {
if (module) {
// Get a new function from the testing module.
function_ = nullptr;
......@@ -444,6 +447,7 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
WasmFunction* function_;
int function_index_;
LocalDeclEncoder local_decls;
SourcePositionTable source_position_table_;
Isolate* isolate() { return main_isolate(); }
Graph* graph() const { return main_graph_; }
......@@ -460,7 +464,8 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
void Build(const byte* start, const byte* end) {
// Build the TurboFan graph.
local_decls.Prepend(&start, &end);
TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig, start, end);
TestBuildingGraph(main_zone(), &jsgraph, testing_module_, sig,
&source_position_table_, start, end);
delete[] start;
}
......@@ -479,16 +484,26 @@ class WasmFunctionCompiler : public HandleAndZoneScope,
}
CompilationInfo info(debug_name_, this->isolate(), this->zone(),
Code::ComputeFlags(Code::WASM_FUNCTION));
Handle<Code> result =
Pipeline::GenerateCodeForTesting(&info, desc, this->graph());
compiler::ZonePool zone_pool(this->isolate()->allocator());
compiler::ZonePool::Scope pipeline_zone_scope(&zone_pool);
Pipeline pipeline(&info);
pipeline.InitializeWasmCompilation(this->zone(), &zone_pool, this->graph(),
&source_position_table_);
Handle<Code> code;
if (pipeline.ExecuteWasmCompilation(desc)) {
code = pipeline.FinalizeWasmCompilation(desc);
} else {
code = Handle<Code>::null();
}
pipeline_zone_scope.Destroy();
#ifdef ENABLE_DISASSEMBLER
if (!result.is_null() && FLAG_print_opt_code) {
if (!code.is_null() && FLAG_print_opt_code) {
OFStream os(stdout);
result->Disassemble("wasm code", os);
code->Disassemble("wasm code", os);
}
#endif
return result;
return code;
}
uint32_t CompileAndAdd(uint16_t sig_index = 0) {
......
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