Commit e51323de authored by ahaas's avatar ahaas Committed by Commit bot

[wasm] Generated the framework in wasm-module for parallel compilation.

I introduced a new flag, --wasm-parallel-compilation, which turns on
parallel compilation of wasm modules. If parallel compilation is turned
on, then the compilation of wasm functions is split into three phases,
initialization, execution, and finalization. The execution phase is the
phase which is going to contain all the code that can be executed in
parallel. At the moment the execution phase is still empty.

R=titzer@chromium.org

Review-Url: https://codereview.chromium.org/1928933002
Cr-Commit-Position: refs/heads/master@{#35875}
parent 2950df96
......@@ -2856,8 +2856,8 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
}
std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
Zone* zone, wasm::ErrorThrower& thrower, Isolate* isolate,
wasm::ModuleEnv*& module_env, const wasm::WasmFunction& function,
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) {
......@@ -2873,16 +2873,16 @@ std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine);
SourcePositionTable* source_position_table =
new (zone) SourcePositionTable(graph);
WasmGraphBuilder builder(zone, jsgraph, function.sig, source_position_table);
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,
module_env->module->module_start + function.code_end_offset};
module_env, function->sig, module_env->module->module_start,
module_env->module->module_start + function->code_start_offset,
module_env->module->module_start + function->code_end_offset};
wasm::TreeResult result =
wasm::BuildTFGraph(isolate->allocator(), &builder, body);
if (machine->Is32()) {
Int64Lowering r(graph, machine, common, zone, function.sig);
Int64Lowering r(graph, machine, common, zone, function->sig);
r.LowerGraph();
}
......@@ -2893,14 +2893,14 @@ std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
}
// Add the function as another context for the exception
ScopedVector<char> buffer(128);
wasm::WasmName name =
module_env->module->GetName(function.name_offset, function.name_length);
wasm::WasmName name = module_env->module->GetName(function->name_offset,
function->name_length);
SNPrintF(buffer, "Compiling WASM function #%d:%.*s failed:",
function.func_index, name.length(), name.start());
thrower.Failed(buffer.start(), result);
function->func_index, name.length(), name.start());
thrower->Failed(buffer.start(), result);
return std::make_pair(nullptr, nullptr);
}
int index = static_cast<int>(function.func_index);
int index = static_cast<int>(function->func_index);
if (index >= FLAG_trace_wasm_ast_start && index < FLAG_trace_wasm_ast_end) {
PrintAst(isolate->allocator(), body);
}
......@@ -2911,15 +2911,15 @@ std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction(
}
// Helper function to compile a single function.
Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction& function) {
const wasm::WasmFunction* function) {
HistogramTimerScope wasm_compile_function_time_scope(
isolate->counters()->wasm_compile_function_time());
if (FLAG_trace_wasm_compiler) {
OFStream os(stdout);
os << "Compiling WASM function "
<< wasm::WasmFunctionName(&function, module_env) << std::endl;
<< wasm::WasmFunctionName(function, module_env) << std::endl;
os << std::endl;
}
......@@ -2942,7 +2942,7 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
}
// Run the compiler pipeline to generate machine code.
CallDescriptor* descriptor = wasm::ModuleEnv::GetWasmCallDescriptor(
jsgraph->graph()->zone(), function.sig);
jsgraph->graph()->zone(), function->sig);
if (jsgraph->machine()->Is32()) {
descriptor = module_env->GetI32WasmCallDescriptor(jsgraph->graph()->zone(),
descriptor);
......@@ -2956,12 +2956,12 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
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);
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);
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");
......@@ -2978,10 +2978,10 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
buffer.Dispose();
if (!code.is_null()) {
RecordFunctionCompilation(Logger::FUNCTION_TAG, &info, "WASM_function",
function.func_index,
module_env->module->GetName(
function.name_offset, function.name_length));
RecordFunctionCompilation(
Logger::FUNCTION_TAG, &info, "WASM_function", function->func_index,
module_env->module->GetName(function->name_offset,
function->name_length));
}
if (FLAG_trace_wasm_decode_time) {
......@@ -2989,7 +2989,8 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
PrintF(
"wasm-compile ok: %d bytes, %0.3f ms decode, %d nodes, %0.3f ms "
"compile\n",
static_cast<int>(function.code_end_offset - function.code_start_offset),
static_cast<int>(function->code_end_offset -
function->code_start_offset),
decode_ms, static_cast<int>(jsgraph->graph()->NodeCount()), compile_ms);
}
// TODO(bradnelson): Improve histogram handling of size_t.
......@@ -2999,6 +3000,49 @@ Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
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 CompileWasmFunction(thrower_, isolate_, module_env_, function_);
}
wasm::ErrorThrower* thrower_;
Isolate* isolate_;
wasm::ModuleEnv* module_env_;
const wasm::WasmFunction* function_;
};
WasmCompilationUnit* CreateWasmCompilationUnit(
wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function) {
return new WasmCompilationUnit(thrower, isolate, module_env, function);
}
void ExecuteCompilation(WasmCompilationUnit* unit) {
unit->ExecuteCompilation();
}
Handle<Code> FinishCompilation(WasmCompilationUnit* unit) {
Handle<Code> result = unit->FinishCompilation();
delete unit;
return result;
}
} // namespace compiler
} // namespace internal
......
......@@ -20,6 +20,7 @@ class JSGraph;
class Graph;
class Operator;
class SourcePositionTable;
class WasmCompilationUnit;
}
namespace wasm {
......@@ -35,9 +36,9 @@ typedef compiler::JSGraph TFGraph;
namespace compiler {
// Compiles a single function, producing a code object.
Handle<Code> CompileWasmFunction(wasm::ErrorThrower& thrower, Isolate* isolate,
Handle<Code> CompileWasmFunction(wasm::ErrorThrower* thrower, Isolate* isolate,
wasm::ModuleEnv* module_env,
const wasm::WasmFunction& function);
const wasm::WasmFunction* function);
// Wraps a JS function, producing a code object that can be called from WASM.
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, wasm::ModuleEnv* module,
......@@ -52,6 +53,16 @@ Handle<JSFunction> CompileJSToWasmWrapper(
Isolate* isolate, wasm::ModuleEnv* module, Handle<String> name,
Handle<Code> wasm_code, Handle<JSObject> module_object, uint32_t index);
WasmCompilationUnit* CreateWasmCompilationUnit(
wasm::ErrorThrower* thrower, Isolate* isolate, wasm::ModuleEnv* module_env,
const wasm::WasmFunction* function);
void ExecuteCompilation(WasmCompilationUnit* unit);
int GetIndexOfWasmCompilationUnit(WasmCompilationUnit* unit);
Handle<Code> FinishCompilation(WasmCompilationUnit* unit);
// Abstracts details of building TurboFan graph nodes for WASM to separate
// the WASM decoder from the internal details of TurboFan.
class WasmTrapHelper;
......
......@@ -462,6 +462,7 @@ DEFINE_BOOL(turbo_stress_instruction_scheduling, false,
// Flags for native WebAssembly.
DEFINE_BOOL(expose_wasm, false, "expose WASM interface to JavaScript")
DEFINE_BOOL(wasm_parallel_compilation, false, "compile WASM code in parallel")
DEFINE_BOOL(trace_wasm_encoder, false, "trace encoding of wasm code")
DEFINE_BOOL(trace_wasm_decoder, false, "trace decoding of wasm code")
DEFINE_BOOL(trace_wasm_decode_time, false, "trace decoding time of wasm code")
......
......@@ -491,12 +491,37 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
isolate->counters()->wasm_functions_per_module()->AddSample(
static_cast<int>(functions.size()));
std::vector<compiler::WasmCompilationUnit*> compilation_units(
functions.size());
if (FLAG_wasm_parallel_compilation) {
// Create a placeholder code object for all functions.
// TODO(ahaas): Maybe we could skip this for external functions.
for (uint32_t i = 0; i < functions.size(); i++) {
linker.GetFunctionCode(i);
}
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
i++) {
if (!functions[i].external) {
compilation_units[i] = compiler::CreateWasmCompilationUnit(
&thrower, isolate, &module_env, &functions[i]);
}
}
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
i++) {
if (!functions[i].external) {
compiler::ExecuteCompilation(compilation_units[i]);
}
}
}
// First pass: compile each function and initialize the code table.
index = FLAG_skip_compiling_wasm_funcs;
while (index < functions.size()) {
const WasmFunction& func = functions[index];
for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
i++) {
const WasmFunction& func = functions[i];
if (thrower.error()) break;
DCHECK_EQ(index, func.func_index);
DCHECK_EQ(i, func.func_index);
WasmName str = GetName(func.name_offset, func.name_length);
WasmName str_null = {nullptr, 0};
......@@ -506,36 +531,39 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
if (func.external) {
// Lookup external function in FFI object.
MaybeHandle<JSFunction> function =
LookupFunction(thrower, factory, ffi, index, str, str_null);
LookupFunction(thrower, factory, ffi, i, str, str_null);
if (function.is_null()) return MaybeHandle<JSObject>();
code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
function.ToHandleChecked(),
func.sig, str, str_null);
} else {
// Compile the function.
code =
compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
if (FLAG_wasm_parallel_compilation) {
code = compiler::FinishCompilation(compilation_units[i]);
} else {
// Compile the function.
code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
&func);
}
if (code.is_null()) {
thrower.Error("Compilation of #%d:%.*s failed.", index, str.length(),
thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(),
str.start());
return MaybeHandle<JSObject>();
}
if (func.exported) {
function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object, index);
isolate, &module_env, name, code, instance.js_object, i);
}
}
if (!code.is_null()) {
// Install the code into the linker table.
linker.Finish(index, code);
code_table->set(index, *code);
linker.Finish(i, code);
code_table->set(i, *code);
}
if (func.exported) {
// Exported functions are installed as read-only properties on the
// module.
JSObject::AddProperty(instance.js_object, name, function, READ_ONLY);
}
index++;
}
// Second pass: patch all direct call sites.
......@@ -547,7 +575,6 @@ MaybeHandle<JSObject> WasmModule::Instantiate(Isolate* isolate,
// Create and populate the exports object.
//-------------------------------------------------------------------------
if (export_table.size() > 0 || mem_export) {
index = 0;
// Create the "exports" object.
Handle<JSFunction> object_function = Handle<JSFunction>(
isolate->native_context()->object_function(), isolate);
......@@ -682,7 +709,7 @@ int32_t CompileAndRunWasmModule(Isolate* isolate, WasmModule* module) {
if (!func.external) {
// Compile the function and install it in the code table.
Handle<Code> code =
compiler::CompileWasmFunction(thrower, isolate, &module_env, func);
compiler::CompileWasmFunction(&thrower, isolate, &module_env, &func);
if (!code.is_null()) {
if (func.exported) {
main_code = code;
......
......@@ -16,6 +16,7 @@ namespace internal {
namespace compiler {
class CallDescriptor;
class WasmCompilationUnit;
}
namespace wasm {
......
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