Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(422)

Unified Diff: src/wasm/wasm-module.cc

Issue 1965243003: Revert of [wasm] Implement parallel compilation. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/flag-definitions.h ('k') | test/mjsunit/wasm/parallel_compilation.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/wasm/wasm-module.cc
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc
index f880d03e34112320947c015ad23d3911a6bd71d8..9ec439d4b5192229dea9573907e2236830cc3135 100644
--- a/src/wasm/wasm-module.cc
+++ b/src/wasm/wasm-module.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/base/atomic-utils.h"
#include "src/macro-assembler.h"
#include "src/objects.h"
#include "src/property-descriptor.h"
@@ -130,11 +129,11 @@
// Create a placeholder code object and encode the corresponding index in
// the {constant_pool_offset} field of the code object.
// TODO(titzer): placeholder code objects are somewhat dangerous.
+ Handle<Code> self(nullptr, isolate_);
byte buffer[] = {0, 0, 0, 0, 0, 0, 0, 0}; // fake instructions.
CodeDesc desc = {buffer, 8, 8, 0, 0, nullptr};
Handle<Code> code = isolate_->factory()->NewCode(
- desc, Code::KindField::encode(Code::WASM_FUNCTION),
- Handle<Object>::null());
+ desc, Code::KindField::encode(Code::WASM_FUNCTION), self);
code->set_constant_pool_offset(index + kPlaceholderMarker);
placeholder_code_[index] = code;
function_code_[index] = code;
@@ -396,245 +395,6 @@
return Handle<JSFunction>::cast(function);
}
-namespace {
-// Fetches the compilation unit of a wasm function and executes its parallel
-// phase.
-bool FetchAndExecuteCompilationUnit(
- Isolate* isolate,
- std::vector<compiler::WasmCompilationUnit*>* compilation_units,
- std::queue<compiler::WasmCompilationUnit*>* executed_units,
- base::Mutex* result_mutex, base::AtomicNumber<size_t>* next_unit) {
- DisallowHeapAllocation no_allocation;
- DisallowHandleAllocation no_handles;
- DisallowHandleDereference no_deref;
- DisallowCodeDependencyChange no_dependency_change;
-
- // - 1 because AtomicIntrement returns the value after the atomic increment.
- size_t index = next_unit->Increment(1) - 1;
- if (index >= compilation_units->size()) {
- return false;
- }
-
- compiler::WasmCompilationUnit* unit = compilation_units->at(index);
- if (unit != nullptr) {
- compiler::ExecuteCompilation(unit);
- {
- base::LockGuard<base::Mutex> guard(result_mutex);
- executed_units->push(unit);
- }
- }
- return true;
-}
-
-class WasmCompilationTask : public CancelableTask {
- public:
- WasmCompilationTask(
- Isolate* isolate,
- std::vector<compiler::WasmCompilationUnit*>* compilation_units,
- std::queue<compiler::WasmCompilationUnit*>* executed_units,
- base::Semaphore* on_finished, base::Mutex* result_mutex,
- base::AtomicNumber<size_t>* next_unit)
- : CancelableTask(isolate),
- isolate_(isolate),
- compilation_units_(compilation_units),
- executed_units_(executed_units),
- on_finished_(on_finished),
- result_mutex_(result_mutex),
- next_unit_(next_unit) {}
-
- void RunInternal() override {
- while (FetchAndExecuteCompilationUnit(isolate_, compilation_units_,
- executed_units_, result_mutex_,
- next_unit_)) {
- }
- on_finished_->Signal();
- }
-
- Isolate* isolate_;
- std::vector<compiler::WasmCompilationUnit*>* compilation_units_;
- std::queue<compiler::WasmCompilationUnit*>* executed_units_;
- base::Semaphore* on_finished_;
- base::Mutex* result_mutex_;
- base::AtomicNumber<size_t>* next_unit_;
-};
-
-void record_code_size(uint32_t& total_code_size, Code* code) {
- if (FLAG_print_wasm_code_size) {
- total_code_size += code->body_size() + code->relocation_info()->length();
- }
-}
-
-bool CompileWrappersToImportedFunctions(Isolate* isolate, WasmModule* module,
- const Handle<JSReceiver> ffi,
- WasmModuleInstance* instance,
- ErrorThrower* thrower, Factory* factory,
- ModuleEnv* module_env,
- uint32_t& total_code_size) {
- uint32_t index = 0;
- if (module->import_table.size() > 0) {
- instance->import_code.reserve(module->import_table.size());
- for (const WasmImport& import : module->import_table) {
- WasmName module_name = module->GetNameOrNull(import.module_name_offset,
- import.module_name_length);
- WasmName function_name = module->GetNameOrNull(
- import.function_name_offset, import.function_name_length);
- MaybeHandle<JSFunction> function = LookupFunction(
- *thrower, factory, ffi, index, module_name, function_name);
- if (function.is_null()) return false;
-
- Handle<Code> code = compiler::CompileWasmToJSWrapper(
- isolate, module_env, function.ToHandleChecked(), import.sig,
- module_name, function_name);
- instance->import_code.push_back(code);
- record_code_size(total_code_size, *code);
- index++;
- }
- }
- return true;
-}
-
-void InitializeParallelCompilation(
- Isolate* isolate, std::vector<WasmFunction>& functions,
- std::vector<compiler::WasmCompilationUnit*>& compilation_units,
- ModuleEnv& module_env, ErrorThrower& thrower) {
- // 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++) {
- module_env.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], i);
- } else {
- compilation_units[i] = nullptr;
- }
- }
-}
-
-uint32_t* StartCompilationTasks(
- Isolate* isolate,
- std::vector<compiler::WasmCompilationUnit*>& compilation_units,
- std::queue<compiler::WasmCompilationUnit*>& executed_units,
- const base::SmartPointer<base::Semaphore>& pending_tasks,
- base::Mutex& result_mutex, base::AtomicNumber<size_t>& next_unit) {
- const size_t num_tasks =
- Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
- V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
- uint32_t* task_ids = new uint32_t[num_tasks];
- for (size_t i = 0; i < num_tasks; i++) {
- WasmCompilationTask* task =
- new WasmCompilationTask(isolate, &compilation_units, &executed_units,
- pending_tasks.get(), &result_mutex, &next_unit);
- task_ids[i] = task->id();
- V8::GetCurrentPlatform()->CallOnBackgroundThread(
- task, v8::Platform::kShortRunningTask);
- }
- return task_ids;
-}
-
-void WaitForCompilationTasks(
- Isolate* isolate, uint32_t* task_ids,
- const base::SmartPointer<base::Semaphore>& pending_tasks) {
- const size_t num_tasks =
- Min(static_cast<size_t>(FLAG_wasm_num_compilation_tasks),
- V8::GetCurrentPlatform()->NumberOfAvailableBackgroundThreads());
- for (size_t i = 0; i < num_tasks; i++) {
- // If the task has not started yet, then we abort it. Otherwise we wait for
- // it to finish.
- if (!isolate->cancelable_task_manager()->TryAbort(task_ids[i])) {
- pending_tasks->Wait();
- }
- }
-}
-
-void FinishCompilationUnits(
- WasmModule* module,
- std::queue<compiler::WasmCompilationUnit*>& executed_units,
- std::vector<Handle<Code>>& results, base::Mutex& result_mutex) {
- while (!executed_units.empty()) {
- compiler::WasmCompilationUnit* unit = nullptr;
- {
- base::LockGuard<base::Mutex> guard(&result_mutex);
- unit = executed_units.front();
- executed_units.pop();
- }
- int j = compiler::GetIndexOfWasmCompilationUnit(unit);
- if (!module->functions[j].external) {
- results[j] = compiler::FinishCompilation(unit);
- }
- }
-}
-
-bool FinishCompilation(Isolate* isolate, WasmModule* module,
- const Handle<JSReceiver> ffi,
- const std::vector<Handle<Code>>& results,
- const WasmModuleInstance& instance,
- const Handle<FixedArray>& code_table,
- ErrorThrower& thrower, Factory* factory,
- ModuleEnv& module_env, uint32_t& total_code_size,
- PropertyDescriptor& desc) {
- for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
- i < module->functions.size(); i++) {
- const WasmFunction& func = module->functions[i];
- if (thrower.error()) break;
-
- DCHECK_EQ(i, func.func_index);
- WasmName str = module->GetName(func.name_offset, func.name_length);
- WasmName str_null = {nullptr, 0};
- Handle<String> name = factory->InternalizeUtf8String(str);
- Handle<Code> code = Handle<Code>::null();
- Handle<JSFunction> function = Handle<JSFunction>::null();
- if (func.external) {
- // Lookup external function in FFI object.
- MaybeHandle<JSFunction> function =
- LookupFunction(thrower, factory, ffi, i, str, str_null);
- if (function.is_null()) {
- return false;
- }
- code = compiler::CompileWasmToJSWrapper(isolate, &module_env,
- function.ToHandleChecked(),
- func.sig, str, str_null);
- } else {
- if (FLAG_wasm_num_compilation_tasks != 0) {
- code = results[i];
- } else {
- // Compile the function.
- code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
- &func);
- }
- if (code.is_null()) {
- thrower.Error("Compilation of #%d:%.*s failed.", i, str.length(),
- str.start());
- return false;
- }
- if (func.exported) {
- function = compiler::CompileJSToWasmWrapper(
- isolate, &module_env, name, code, instance.js_object, i);
- record_code_size(total_code_size, function->code());
- }
- }
- if (!code.is_null()) {
- // Install the code into the linker table.
- module_env.linker->Finish(i, code);
- code_table->set(i, *code);
- record_code_size(total_code_size, *code);
- }
- if (func.exported) {
- // Exported functions are installed as read-only properties on the
- // module.
- desc.set_value(function);
- Maybe<bool> status = JSReceiver::DefineOwnProperty(
- isolate, instance.js_object, name, &desc, Object::THROW_ON_ERROR);
- if (!status.IsJust())
- thrower.Error("export of %.*s failed.", str.length(), str.start());
- }
- }
- return true;
-}
-} // namespace
-
// Instantiates a wasm module as a JSObject.
// * allocates a backing store of {mem_size} bytes.
// * installs a named property "memory" for that buffer if exported
@@ -656,6 +416,10 @@
// objects created for this module.
// TODO(titzer): switch this to TRACE_EVENT
uint32_t total_code_size = 0;
+ auto record_code_size = [&total_code_size](Code* code) {
+ if (FLAG_print_wasm_code_size)
+ total_code_size += code->body_size() + code->relocation_info()->length();
+ };
//-------------------------------------------------------------------------
// Allocate the instance and its JS counterpart.
@@ -702,6 +466,10 @@
HistogramTimerScope wasm_compile_module_time_scope(
isolate->counters()->wasm_compile_module_time());
+ //-------------------------------------------------------------------------
+ // Compile wrappers to imported functions.
+ //-------------------------------------------------------------------------
+ uint32_t index = 0;
instance.function_table = BuildFunctionTable(isolate, this);
WasmLinker linker(isolate, functions.size());
ModuleEnv module_env;
@@ -710,14 +478,25 @@
module_env.linker = &linker;
module_env.origin = origin;
- //-------------------------------------------------------------------------
- // Compile wrappers to imported functions.
- //-------------------------------------------------------------------------
- if (!CompileWrappersToImportedFunctions(isolate, this, ffi, &instance,
- &thrower, factory, &module_env,
- total_code_size)) {
- return MaybeHandle<JSObject>();
- }
+ if (import_table.size() > 0) {
+ instance.import_code.reserve(import_table.size());
+ for (const WasmImport& import : import_table) {
+ WasmName module_name =
+ GetNameOrNull(import.module_name_offset, import.module_name_length);
+ WasmName function_name = GetNameOrNull(import.function_name_offset,
+ import.function_name_length);
+ MaybeHandle<JSFunction> function = LookupFunction(
+ thrower, factory, ffi, index, module_name, function_name);
+ if (function.is_null()) return MaybeHandle<JSObject>();
+ Handle<Code> code = compiler::CompileWasmToJSWrapper(
+ isolate, &module_env, function.ToHandleChecked(), import.sig,
+ module_name, function_name);
+ instance.import_code.push_back(code);
+ record_code_size(*code);
+ index++;
+ }
+ }
+
//-------------------------------------------------------------------------
// Compile all functions in the module.
//-------------------------------------------------------------------------
@@ -725,77 +504,103 @@
isolate->counters()->wasm_functions_per_module()->AddSample(
static_cast<int>(functions.size()));
- // Data structures for the parallel compilation.
std::vector<compiler::WasmCompilationUnit*> compilation_units(
functions.size());
std::queue<compiler::WasmCompilationUnit*> executed_units;
std::vector<Handle<Code>> results(functions.size());
- if (FLAG_wasm_num_compilation_tasks != 0) {
- //-----------------------------------------------------------------------
- // For parallel compilation:
- // 1) The main thread allocates a compilation unit for each wasm function
- // and stores them in the vector {compilation_units}.
- // 2) The main thread spawns {WasmCompilationTask} instances which run on
- // the background threads.
- // 3.a) The background threads and the main thread pick one compilation
- // unit at a time and execute the parallel phase of the compilation
- // unit. After finishing the execution of the parallel phase, the
- // result is enqueued in {executed_units}.
- // 3.b) If {executed_units} contains a compilation unit, the main thread
- // dequeues it and finishes the compilation.
- // 4) After the parallel phase of all compilation units has started, the
- // main thread waits for all {WasmCompilationTask} instances to finish.
- // 5) The main thread finishes the compilation.
-
- // Turn on the {CanonicalHandleScope} so that the background threads can
- // use the node cache.
- CanonicalHandleScope canonical(isolate);
-
- // 1) The main thread allocates a compilation unit for each wasm function
- // and stores them in the vector {compilation_units}.
- InitializeParallelCompilation(isolate, functions, compilation_units,
- module_env, thrower);
-
- // Objects for the synchronization with the background threads.
- base::SmartPointer<base::Semaphore> pending_tasks(new base::Semaphore(0));
- base::Mutex result_mutex;
- base::AtomicNumber<size_t> next_unit(
- static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
-
- // 2) The main thread spawns {WasmCompilationTask} instances which run on
- // the background threads.
- base::SmartArrayPointer<uint32_t> task_ids(
- StartCompilationTasks(isolate, compilation_units, executed_units,
- pending_tasks, result_mutex, next_unit));
-
- // 3.a) The background threads and the main thread pick one compilation
- // unit at a time and execute the parallel phase of the compilation
- // unit. After finishing the execution of the parallel phase, the
- // result is enqueued in {executed_units}.
- while (FetchAndExecuteCompilationUnit(isolate, &compilation_units,
- &executed_units, &result_mutex,
- &next_unit)) {
- // 3.b) If {executed_units} contains a compilation unit, the main thread
- // dequeues it and finishes the compilation unit. Compilation units
- // are finished concurrently to the background threads to save
- // memory.
- FinishCompilationUnits(this, executed_units, results, result_mutex);
- }
- // 4) After the parallel phase of all compilation units has started, the
- // main thread waits for all {WasmCompilationTask} instances to finish.
- WaitForCompilationTasks(isolate, task_ids.get(), pending_tasks);
- // Finish the compilation of the remaining compilation units.
- FinishCompilationUnits(this, executed_units, results, result_mutex);
- }
- // 5) The main thread finishes the compilation.
- if (!FinishCompilation(isolate, this, ffi, results, instance, code_table,
- thrower, factory, module_env, total_code_size,
- desc)) {
- return MaybeHandle<JSObject>();
- }
-
- // Patch all direct call sites.
+ 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], i);
+ }
+ }
+
+ index = FLAG_skip_compiling_wasm_funcs;
+ while (true) {
+ while (!executed_units.empty()) {
+ 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;
+ }
+ }
+ }
+
+ // First pass: compile each function and initialize the code table.
+ for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
+ i++) {
+ const WasmFunction& func = functions[i];
+ if (thrower.error()) break;
+ DCHECK_EQ(i, func.func_index);
+
+ WasmName str = GetName(func.name_offset, func.name_length);
+ WasmName str_null = {nullptr, 0};
+ Handle<String> name = factory->InternalizeUtf8String(str);
+ Handle<Code> code = Handle<Code>::null();
+ Handle<JSFunction> function = Handle<JSFunction>::null();
+ if (func.external) {
+ // Lookup external function in FFI object.
+ MaybeHandle<JSFunction> function =
+ 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 {
+ if (FLAG_wasm_parallel_compilation) {
+ code = results[i];
+ } else {
+ // Compile the function.
+ code = compiler::CompileWasmFunction(&thrower, isolate, &module_env,
+ &func);
+ }
+ if (code.is_null()) {
+ 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, i);
+ record_code_size(function->code());
+ }
+ }
+ if (!code.is_null()) {
+ // Install the code into the linker table.
+ linker.Finish(i, code);
+ code_table->set(i, *code);
+ record_code_size(*code);
+ }
+ if (func.exported) {
+ // Exported functions are installed as read-only properties on the
+ // module.
+ desc.set_value(function);
+ Maybe<bool> status = JSReceiver::DefineOwnProperty(
+ isolate, instance.js_object, name, &desc, Object::THROW_ON_ERROR);
+ if (!status.IsJust())
+ thrower.Error("export of %.*s failed.", str.length(), str.start());
+ }
+ }
+
+ // Second pass: patch all direct call sites.
linker.Link(instance.function_table, this->function_table);
instance.js_object->SetInternalField(kWasmModuleFunctionTable,
Smi::FromInt(0));
@@ -822,7 +627,7 @@
Handle<JSFunction> function = compiler::CompileJSToWasmWrapper(
isolate, &module_env, name, code, instance.js_object,
exp.func_index);
- record_code_size(total_code_size, function->code());
+ record_code_size(function->code());
desc.set_value(function);
Maybe<bool> status = JSReceiver::DefineOwnProperty(
isolate, exports_object, name, &desc, Object::THROW_ON_ERROR);
« no previous file with comments | « src/flag-definitions.h ('k') | test/mjsunit/wasm/parallel_compilation.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698