Commit 18c380c3 authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Split the wasm compilation into two phases for parallel compilation.

Graph construction, graph scheduling, instruction selection, and register
allocation has been moved to ExecuteCompilation, which will eventually be
executed on the background threads. Code generation remains in
FinishCompilation because it has to be executed by the main thread.

Additionally, WasmCompilationUnits are finished more eagerly in
wasm-module.cc to save memory.

R=titzer@chromium.org

Review-Url: https://codereview.chromium.org/1942773002
Cr-Commit-Position: refs/heads/master@{#35973}
parent c89e6eb5
...@@ -2956,85 +2956,105 @@ std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction( ...@@ -2956,85 +2956,105 @@ std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
return std::make_pair(jsgraph, source_position_table); return std::make_pair(jsgraph, source_position_table);
} }
// Helper function to compile a single function. class WasmCompilationUnit {
Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate, public:
WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env, wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function) { const wasm::WasmFunction* function, uint32_t index)
: thrower_(thrower),
isolate_(isolate),
module_env_(module_env),
function_(function),
compilation_zone_(isolate->allocator()),
info_(function->name_length != 0
? module_env->module->GetNameOrNull(function->name_offset,
function->name_length)
: ArrayVector("wasm"),
isolate, &compilation_zone_,
Code::ComputeFlags(Code::WASM_FUNCTION)),
job_(),
index_(index),
ok_(true) {}
void ExecuteCompilation() {
HistogramTimerScope wasm_compile_function_time_scope( HistogramTimerScope wasm_compile_function_time_scope(
isolate->counters()->wasm_compile_function_time()); isolate_->counters()->wasm_compile_function_time());
if (FLAG_trace_wasm_compiler) { if (FLAG_trace_wasm_compiler) {
OFStream os(stdout); OFStream os(stdout);
os << "Compiling WASM function " os << "Compiling WASM function "
<< wasm::WasmFunctionName(function, module_env) << std::endl; << wasm::WasmFunctionName(function_, module_env_) << std::endl;
os << std::endl; os << std::endl;
} }
compiler::ZonePool zone_pool(isolate->allocator());
compiler::ZonePool::Scope graph_zone_scope(&zone_pool);
double decode_ms = 0; double decode_ms = 0;
size_t node_count = 0;
Zone zone(isolate_->allocator());
std::pair<JSGraph*, SourcePositionTable*> graph_result = std::pair<JSGraph*, SourcePositionTable*> graph_result =
BuildGraphForWasmFunction(graph_zone_scope.zone(), thrower, isolate, BuildGraphForWasmFunction(&zone, thrower_, isolate_, module_env_,
module_env, function, &decode_ms); function_, &decode_ms);
JSGraph* jsgraph = graph_result.first; JSGraph* jsgraph = graph_result.first;
SourcePositionTable* source_positions = graph_result.second; SourcePositionTable* source_positions = graph_result.second;
if (jsgraph == nullptr) { if (jsgraph == nullptr) {
return Handle<Code>::null(); ok_ = false;
return;
} }
base::ElapsedTimer compile_timer; base::ElapsedTimer pipeline_timer;
if (FLAG_trace_wasm_decode_time) { if (FLAG_trace_wasm_decode_time) {
compile_timer.Start(); node_count = jsgraph->graph()->NodeCount();
pipeline_timer.Start();
} }
// Run the compiler pipeline to generate machine code. // Run the compiler pipeline to generate machine code.
CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor( CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor(
jsgraph->graph()->zone(), function->sig); &compilation_zone_, function_->sig);
if (jsgraph->machine()->Is32()) { if (jsgraph->machine()->Is32()) {
descriptor = module_env->GetI32WasmCallDescriptor(jsgraph->graph()->zone(), descriptor =
descriptor); module_env_->GetI32WasmCallDescriptor(&compilation_zone_, descriptor);
}
Code::Flags flags = Code::ComputeFlags(Code::WASM_FUNCTION);
// add flags here if a meaningful name is helpful for debugging.
bool debugging =
#if DEBUG
true;
#else
FLAG_print_opt_code || FLAG_trace_turbo || FLAG_trace_turbo_graph;
#endif
Vector<const char> func_name = module_env->module->GetNameOrNull(
function->name_offset, function->name_length);
Vector<char> buffer;
if (func_name.is_empty()) {
if (debugging) {
buffer = Vector<char>::New(128);
int chars = SNPrintF(buffer, "WASM_function_#%d", function->func_index);
func_name = Vector<const char>::cast(buffer.SubVector(0, chars));
} else {
func_name = ArrayVector("wasm");
} }
job_.Reset(Pipeline::NewWasmCompilationJob(&info_, jsgraph->graph(),
descriptor, source_positions));
ok_ = job_->OptimizeGraph() == CompilationJob::SUCCEEDED;
// TODO(bradnelson): Improve histogram handling of size_t.
isolate_->counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
if (FLAG_trace_wasm_decode_time) {
double pipeline_ms = pipeline_timer.Elapsed().InMillisecondsF();
PrintF(
"wasm-compilation phase 1 ok: %d bytes, %0.3f ms decode, %zu nodes, "
"%0.3f ms pipeline\n",
static_cast<int>(function_->code_end_offset -
function_->code_start_offset),
decode_ms, node_count, pipeline_ms);
} }
CompilationInfo info(func_name, isolate, jsgraph->graph()->zone(), flags);
base::SmartPointer<CompilationJob> job(Pipeline::NewWasmCompilationJob(
&info, jsgraph->graph(), descriptor, source_positions));
Handle<Code> code = Handle<Code>::null();
if (job->OptimizeGraph() == CompilationJob::SUCCEEDED &&
job->GenerateCode() == CompilationJob::SUCCEEDED) {
code = info.code();
} }
buffer.Dispose(); Handle<Code> FinishCompilation() {
if (!ok_) {
if (!code.is_null()) { return Handle<Code>::null();
}
if (job_->GenerateCode() != CompilationJob::SUCCEEDED) {
return Handle<Code>::null();
}
base::ElapsedTimer compile_timer;
if (FLAG_trace_wasm_decode_time) {
compile_timer.Start();
}
Handle<Code> code = info_.code();
DCHECK(!code.is_null());
DCHECK(code->deoptimization_data() == nullptr || DCHECK(code->deoptimization_data() == nullptr ||
code->deoptimization_data()->length() == 0); code->deoptimization_data()->length() == 0);
Handle<FixedArray> deopt_data = Handle<FixedArray> deopt_data =
isolate->factory()->NewFixedArray(2, TENURED); isolate_->factory()->NewFixedArray(2, TENURED);
if (!module_env->instance->js_object.is_null()) { if (!module_env_->instance->js_object.is_null()) {
deopt_data->set(0, *module_env->instance->js_object); deopt_data->set(0, *module_env_->instance->js_object);
deopt_data->set(1, Smi::FromInt(function->func_index)); deopt_data->set(1, Smi::FromInt(function_->func_index));
} else if (func_name.start() != nullptr) { } else if (info_.GetDebugName().get() != nullptr) {
MaybeHandle<String> maybe_name = MaybeHandle<String> maybe_name = isolate_->factory()->NewStringFromUtf8(
isolate->factory()->NewStringFromUtf8(func_name); CStrVector(info_.GetDebugName().get()));
if (!maybe_name.is_null()) if (!maybe_name.is_null())
deopt_data->set(0, *maybe_name.ToHandleChecked()); deopt_data->set(0, *maybe_name.ToHandleChecked());
} }
...@@ -3042,71 +3062,62 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate, ...@@ -3042,71 +3062,62 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
code->set_deoptimization_data(*deopt_data); code->set_deoptimization_data(*deopt_data);
RecordFunctionCompilation( RecordFunctionCompilation(
Logger::FUNCTION_TAG, &info, "WASM_function", function->func_index, Logger::FUNCTION_TAG, &info_, "WASM_function", function_->func_index,
module_env->module->GetName(function->name_offset, module_env_->module->GetName(function_->name_offset,
function->name_length)); function_->name_length));
}
if (FLAG_trace_wasm_decode_time) { if (FLAG_trace_wasm_decode_time) {
double compile_ms = compile_timer.Elapsed().InMillisecondsF(); double compile_ms = compile_timer.Elapsed().InMillisecondsF();
PrintF( PrintF("wasm-code-generation ok: %d bytes, %0.3f ms code generation\n",
"wasm-compile ok: %d bytes, %0.3f ms decode, %d nodes, %0.3f ms " static_cast<int>(function_->code_end_offset -
"compile\n", function_->code_start_offset),
static_cast<int>(function->code_end_offset - compile_ms);
function->code_start_offset),
decode_ms, static_cast<int>(jsgraph->graph()->NodeCount()), compile_ms);
}
// TODO(bradnelson): Improve histogram handling of size_t.
isolate->counters()->wasm_compile_function_peak_memory_bytes()->AddSample(
static_cast<int>(jsgraph->graph()->zone()->allocation_size()));
graph_zone_scope.Destroy();
return code;
}
class WasmCompilationUnit {
public:
WasmCompilationUnit(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function)
: thrower_(thrower),
isolate_(isolate),
module_env_(module_env),
function_(function) {}
void ExecuteCompilation() {
if (function_->external) {
return;
}
// TODO(ahaas): The parallelizable parts of the compilation should move from
// FinishCompilation to here.
} }
Handle<Code> FinishCompilation() { return code;
return CompileWasmFunction(thrower_, isolate_, module_env_, function_);
} }
wasm::ErrorThrower* thrower_; wasm::ErrorThrower* thrower_;
Isolate* isolate_; Isolate* isolate_;
wasm::ModuleEnv* module_env_; wasm::ModuleEnv* module_env_;
const wasm::WasmFunction* function_; const wasm::WasmFunction* function_;
Zone compilation_zone_;
CompilationInfo info_;
base::SmartPointer<CompilationJob> job_;
uint32_t index_;
bool ok_;
}; };
WasmCompilationUnit* CreateWasmCompilationUnit( WasmCompilationUnit* CreateWasmCompilationUnit(
wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env, wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function) { const wasm::WasmFunction* function, uint32_t index) {
return new WasmCompilationUnit(thrower, isolate, module_env, function); return new WasmCompilationUnit(thrower, isolate, module_env, function, index);
} }
void ExecuteCompilation(WasmCompilationUnit* unit) { void ExecuteCompilation(WasmCompilationUnit* unit) {
unit->ExecuteCompilation(); unit->ExecuteCompilation();
} }
uint32_t GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit) {
return unit->index_;
}
Handle<Code> FinishCompilation(WasmCompilationUnit* unit) { Handle<Code> FinishCompilation(WasmCompilationUnit* unit) {
Handle<Code> result = unit->FinishCompilation(); Handle<Code> result = unit->FinishCompilation();
delete unit; delete unit;
return result; return result;
} }
// Helper function to compile a single function.
Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function) {
WasmCompilationUnit* unit =
CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0);
ExecuteCompilation(unit);
return FinishCompilation(unit);
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -55,14 +55,14 @@ Handle<JSFunction> CompileJSToWasmWrapper( ...@@ -55,14 +55,14 @@ Handle<JSFunction> CompileJSToWasmWrapper(
WasmCompilationUnit* CreateWasmCompilationUnit( WasmCompilationUnit* CreateWasmCompilationUnit(
wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env, wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function); const wasm::WasmFunction* function, uint32_t index);
void ExecuteCompilation(WasmCompilationUnit* unit); void ExecuteCompilation(WasmCompilationUnit* unit);
int GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit);
Handle<Code> FinishCompilation(WasmCompilationUnit* unit); Handle<Code> FinishCompilation(WasmCompilationUnit* unit);
uint32_t GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit);
// Abstracts details of building TurboFan graph nodes for WASM to separate // Abstracts details of building TurboFan graph nodes for WASM to separate
// the WASM decoder from the internal details of TurboFan. // the WASM decoder from the internal details of TurboFan.
class WasmTrapHelper; class WasmTrapHelper;
......
...@@ -509,6 +509,9 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, ...@@ -509,6 +509,9 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
std::vector<compiler::WasmCompilationUnit*> compilation_units( std::vector<compiler::WasmCompilationUnit*> compilation_units(
functions.size()); functions.size());
std::queue<compiler::WasmCompilationUnit*> executed_units;
std::vector<Handle<Code>> results(functions.size());
if (FLAG_wasm_parallel_compilation) { if (FLAG_wasm_parallel_compilation) {
// Create a placeholder code object for all functions. // Create a placeholder code object for all functions.
// TODO(ahaas): Maybe we could skip this for external functions. // TODO(ahaas): Maybe we could skip this for external functions.
...@@ -520,14 +523,26 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, ...@@ -520,14 +523,26 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
i++) { i++) {
if (!functions[i].external) { if (!functions[i].external) {
compilation_units[i] = compiler::CreateWasmCompilationUnit( compilation_units[i] = compiler::CreateWasmCompilationUnit(
&thrower, isolate, &module_env, &functions[i]); &thrower, isolate, &module_env, &functions[i], i);
} }
} }
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); index = FLAG_skip_compiling_wasm_funcs;
i++) { while (true) {
if (!functions[i].external) { while (!executed_units.empty()) {
compiler::ExecuteCompilation(compilation_units[i]); compiler::WasmCompilationUnit* unit = executed_units.front();
executed_units.pop();
int i = compiler::GetIndexOfWasmCompilationUnit(unit);
results[i] = compiler::FinishCompilation(unit);
}
if (index < functions.size()) {
if (!functions[index].external) {
compiler::ExecuteCompilation(compilation_units[index]);
executed_units.push(compilation_units[index]);
index++;
}
} else {
break;
} }
} }
} }
...@@ -554,7 +569,7 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate, ...@@ -554,7 +569,7 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
func.sig, str, str_null); func.sig, str, str_null);
} else { } else {
if (FLAG_wasm_parallel_compilation) { if (FLAG_wasm_parallel_compilation) {
code = compiler::FinishCompilation(compilation_units[i]); code = results[i];
} else { } else {
// Compile the function. // Compile the function.
code = compiler::CompileWasmFunction(&thrower, isolate, &module_env, code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
......
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