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

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

Issue 2710603006: [wasm] Move compilation-related methods to CompilationHelper in wasm-module.cc. (Closed)
Patch Set: Smaller buffer Created 3 years, 10 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/compiler/wasm-compiler.cc ('k') | no next file » | 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 34ba2995f9b8f3ffb1102ee4eb2b88ca9635b697..5b24d7702e8f13f5232a9706c1ccb6e7c96b90a0 100644
--- a/src/wasm/wasm-module.cc
+++ b/src/wasm/wasm-module.cc
@@ -76,6 +76,19 @@ bool EnableGuardRegions() {
return FLAG_wasm_guard_pages && kGuardRegionsSupported;
}
+static void RecordStats(Isolate* isolate, Code* code) {
+ isolate->counters()->wasm_generated_code_size()->Increment(code->body_size());
+ isolate->counters()->wasm_reloc_size()->Increment(
+ code->relocation_info()->length());
+}
+
+static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) {
+ DisallowHeapAllocation no_gc;
+ for (int i = 0; i < functions->length(); ++i) {
+ RecordStats(isolate, Code::cast(functions->get(i)));
+ }
+}
+
void* TryAllocateBackingStore(Isolate* isolate, size_t size,
bool enable_guard_regions, bool& is_external) {
is_external = false;
@@ -121,235 +134,415 @@ void FlushICache(Isolate* isolate, Handle<FixedArray> code_table) {
}
}
-// 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 AtomicIncrement returns the value after the atomic increment.
- size_t index = next_unit->Increment(1) - 1;
- if (index >= compilation_units->size()) {
- return false;
- }
+Handle<Script> CreateWasmScript(Isolate* isolate,
+ const ModuleWireBytes& wire_bytes) {
+ Handle<Script> script =
+ isolate->factory()->NewScript(isolate->factory()->empty_string());
+ FixedArray* array = isolate->native_context()->embedder_data();
+ script->set_context_data(array->get(v8::Context::kDebugIdIndex));
+ script->set_type(Script::TYPE_WASM);
- compiler::WasmCompilationUnit* unit = compilation_units->at(index);
- if (unit != nullptr) {
- unit->ExecuteCompilation();
- base::LockGuard<base::Mutex> guard(result_mutex);
- executed_units->push(unit);
- }
- return true;
+ int hash = StringHasher::HashSequentialString(
+ reinterpret_cast<const char*>(wire_bytes.start()), wire_bytes.length(),
+ kZeroHashSeed);
+
+ const int kBufferSize = 32;
+ char buffer[kBufferSize];
+ int url_chars = SNPrintF(ArrayVector(buffer), "wasm://wasm/%08x", hash);
+ DCHECK(url_chars >= 0 && url_chars < kBufferSize);
+ MaybeHandle<String> url_str = isolate->factory()->NewStringFromOneByte(
+ Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), url_chars),
+ TENURED);
+ script->set_source_url(*url_str.ToHandleChecked());
+
+ int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
+ DCHECK(name_chars >= 0 && name_chars < kBufferSize);
+ MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
+ Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
+ TENURED);
+ script->set_name(*name_str.ToHandleChecked());
+
+ return script;
}
-class WasmCompilationTask : public CancelableTask {
+class JSToWasmWrapperCache {
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();
+ Handle<Code> CloneOrCompileJSToWasmWrapper(Isolate* isolate,
+ const wasm::WasmModule* module,
+ Handle<Code> wasm_code,
+ uint32_t index) {
+ const wasm::WasmFunction* func = &module->functions[index];
+ int cached_idx = sig_map_.Find(func->sig);
+ if (cached_idx >= 0) {
+ Handle<Code> code = isolate->factory()->CopyCode(code_cache_[cached_idx]);
+ // Now patch the call to wasm code.
+ for (RelocIterator it(*code, RelocInfo::kCodeTargetMask);; it.next()) {
+ DCHECK(!it.done());
+ Code* target =
+ Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
+ if (target->kind() == Code::WASM_FUNCTION ||
+ target->kind() == Code::WASM_TO_JS_FUNCTION ||
+ target->builtin_index() == Builtins::kIllegal) {
+ it.rinfo()->set_target_address(wasm_code->instruction_start());
+ break;
+ }
+ }
+ return code;
+ }
+
+ Handle<Code> code =
+ compiler::CompileJSToWasmWrapper(isolate, module, wasm_code, index);
+ uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig);
+ DCHECK_EQ(code_cache_.size(), new_cache_idx);
+ USE(new_cache_idx);
+ code_cache_.push_back(code);
+ return code;
}
- 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_;
+ private:
+ // sig_map_ maps signatures to an index in code_cache_.
+ wasm::SignatureMap sig_map_;
+ std::vector<Handle<Code>> code_cache_;
};
-static void RecordStats(Isolate* isolate, Code* code) {
- isolate->counters()->wasm_generated_code_size()->Increment(code->body_size());
- isolate->counters()->wasm_reloc_size()->Increment(
- code->relocation_info()->length());
-}
-
-static void RecordStats(Isolate* isolate, Handle<FixedArray> functions) {
- DisallowHeapAllocation no_gc;
- for (int i = 0; i < functions->length(); ++i) {
- RecordStats(isolate, Code::cast(functions->get(i)));
- }
-}
+// A helper for compiling an entire module.
+class CompilationHelper {
+ public:
+ CompilationHelper(Isolate* isolate, WasmModule* module)
+ : isolate_(isolate), module_(module) {}
+
+ // The actual runnable task that performs compilations in the background.
+ class CompilationTask : public CancelableTask {
+ public:
+ CompilationHelper* helper_;
+ explicit CompilationTask(CompilationHelper* helper)
+ : CancelableTask(helper->isolate_), helper_(helper) {}
+
+ void RunInternal() override {
+ while (helper_->FetchAndExecuteCompilationUnit()) {
+ }
+ helper_->module_->pending_tasks.get()->Signal();
+ }
+ };
-void InitializeParallelCompilation(
- Isolate* isolate, const std::vector<WasmFunction>& functions,
- std::vector<compiler::WasmCompilationUnit*>& compilation_units,
- ModuleBytesEnv& module_env, ErrorThrower* thrower) {
- for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size(); ++i) {
- const WasmFunction* func = &functions[i];
- compilation_units[i] =
- func->imported ? nullptr : new compiler::WasmCompilationUnit(
- thrower, isolate, &module_env, func, i);
+ Isolate* isolate_;
+ WasmModule* module_;
+ std::vector<compiler::WasmCompilationUnit*> compilation_units_;
+ std::queue<compiler::WasmCompilationUnit*> executed_units_;
+ base::Mutex result_mutex_;
+ base::AtomicNumber<size_t> next_unit_;
+
+ // Run by each compilation task and by the main thread.
+ bool FetchAndExecuteCompilationUnit() {
+ DisallowHeapAllocation no_allocation;
+ DisallowHandleAllocation no_handles;
+ DisallowHandleDereference no_deref;
+ DisallowCodeDependencyChange no_dependency_change;
+
+ // - 1 because AtomicIncrement 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) {
+ unit->ExecuteCompilation();
+ base::LockGuard<base::Mutex> guard(&result_mutex_);
+ executed_units_.push(unit);
+ }
+ return true;
+ }
+
+ void InitializeParallelCompilation(const std::vector<WasmFunction>& functions,
+ ModuleBytesEnv& module_env,
+ ErrorThrower* thrower) {
+ compilation_units_.reserve(functions.size());
+ for (uint32_t i = FLAG_skip_compiling_wasm_funcs; i < functions.size();
+ ++i) {
+ const WasmFunction* func = &functions[i];
+ compilation_units_.push_back(
+ func->imported ? nullptr
+ : new compiler::WasmCompilationUnit(
+ thrower, isolate_, &module_env, func, i));
+ }
+ }
+
+ uint32_t* StartCompilationTasks() {
+ 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) {
+ CompilationTask* task = new CompilationTask(this);
+ task_ids[i] = task->id();
+ V8::GetCurrentPlatform()->CallOnBackgroundThread(
+ task, v8::Platform::kShortRunningTask);
+ }
+ return task_ids;
+ }
+
+ void WaitForCompilationTasks(uint32_t* task_ids) {
+ 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]) !=
+ CancelableTaskManager::kTaskAborted) {
+ module_->pending_tasks.get()->Wait();
+ }
+ }
}
-}
-
-uint32_t* StartCompilationTasks(
- Isolate* isolate,
- std::vector<compiler::WasmCompilationUnit*>& compilation_units,
- std::queue<compiler::WasmCompilationUnit*>& executed_units,
- 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, &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,
- 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]) !=
- CancelableTaskManager::kTaskAborted) {
- pending_tasks->Wait();
+ void FinishCompilationUnits(std::vector<Handle<Code>>& results) {
+ while (true) {
+ compiler::WasmCompilationUnit* unit = nullptr;
+ {
+ base::LockGuard<base::Mutex> guard(&result_mutex_);
+ if (executed_units_.empty()) {
+ break;
+ }
+ unit = executed_units_.front();
+ executed_units_.pop();
+ }
+ int j = unit->index();
+ results[j] = unit->FinishCompilation();
+ delete unit;
}
}
-}
-void FinishCompilationUnits(
- std::queue<compiler::WasmCompilationUnit*>& executed_units,
- std::vector<Handle<Code>>& results, base::Mutex& result_mutex) {
- while (true) {
- compiler::WasmCompilationUnit* unit = nullptr;
- {
- base::LockGuard<base::Mutex> guard(&result_mutex);
- if (executed_units.empty()) {
+ void CompileInParallel(ModuleBytesEnv* module_env,
+ std::vector<Handle<Code>>& results,
+ ErrorThrower* thrower) {
+ const WasmModule* module = module_env->module_env.module;
+ // Data structures for the parallel compilation.
+
+ //-----------------------------------------------------------------------
+ // 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 {CompilationTask} 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 {CompilationTask} 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(module->functions, *module_env, thrower);
+
+ // Objects for the synchronization with the background threads.
+ base::AtomicNumber<size_t> next_unit(
+ static_cast<size_t>(FLAG_skip_compiling_wasm_funcs));
+
+ // 2) The main thread spawns {CompilationTask} instances which run on
+ // the background threads.
+ std::unique_ptr<uint32_t[]> task_ids(StartCompilationTasks());
+
+ // 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()) {
+ // 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(results);
+ }
+ // 4) After the parallel phase of all compilation units has started, the
+ // main thread waits for all {CompilationTask} instances to finish.
+ WaitForCompilationTasks(task_ids.get());
+ // Finish the compilation of the remaining compilation units.
+ FinishCompilationUnits(results);
+ }
+
+ void CompileSequentially(ModuleBytesEnv* module_env,
+ std::vector<Handle<Code>>& results,
+ ErrorThrower* thrower) {
+ DCHECK(!thrower->error());
+
+ const WasmModule* module = module_env->module_env.module;
+ for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
+ i < module->functions.size(); ++i) {
+ const WasmFunction& func = module->functions[i];
+ if (func.imported)
+ continue; // Imports are compiled at instantiation time.
+
+ Handle<Code> code = Handle<Code>::null();
+ // Compile the function.
+ code = compiler::WasmCompilationUnit::CompileWasmFunction(
+ thrower, isolate_, module_env, &func);
+ if (code.is_null()) {
+ WasmName str = module_env->wire_bytes.GetName(&func);
+ thrower->CompileError("Compilation of #%d:%.*s failed.", i,
+ str.length(), str.start());
break;
}
- unit = executed_units.front();
- executed_units.pop();
+ results[i] = code;
}
- int j = unit->index();
- results[j] = unit->FinishCompilation();
- delete unit;
}
-}
-void CompileInParallel(Isolate* isolate, ModuleBytesEnv* module_env,
- std::vector<Handle<Code>>& functions,
- ErrorThrower* thrower) {
- const WasmModule* module = module_env->module_env.module;
- // Data structures for the parallel compilation.
- std::vector<compiler::WasmCompilationUnit*> compilation_units(
- module->functions.size());
- std::queue<compiler::WasmCompilationUnit*> executed_units;
-
- //-----------------------------------------------------------------------
- // 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, module->functions, compilation_units,
- *module_env, thrower);
-
- // Objects for the synchronization with the background threads.
- 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.
- std::unique_ptr<uint32_t[]> task_ids(StartCompilationTasks(
- isolate, compilation_units, executed_units, module->pending_tasks.get(),
- 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(executed_units, functions, 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(), module->pending_tasks.get());
- // Finish the compilation of the remaining compilation units.
- FinishCompilationUnits(executed_units, functions, result_mutex);
-}
+ MaybeHandle<WasmModuleObject> CompileToModuleObject(
+ ErrorThrower* thrower, const ModuleWireBytes& wire_bytes,
+ Handle<Script> asm_js_script,
+ Vector<const byte> asm_js_offset_table_bytes) {
+ Factory* factory = isolate_->factory();
+ // The {module_wrapper} will take ownership of the {WasmModule} object,
+ // and it will be destroyed when the GC reclaims the wrapper object.
+ Handle<WasmModuleWrapper> module_wrapper =
+ WasmModuleWrapper::New(isolate_, module_);
+ WasmInstance temp_instance(module_);
+ temp_instance.context = isolate_->native_context();
+ temp_instance.mem_size = WasmModule::kPageSize * module_->min_mem_pages;
+ temp_instance.mem_start = nullptr;
+ temp_instance.globals_start = nullptr;
+
+ // Initialize the indirect tables with placeholders.
+ int function_table_count =
+ static_cast<int>(module_->function_tables.size());
+ Handle<FixedArray> function_tables =
+ factory->NewFixedArray(function_table_count, TENURED);
+ Handle<FixedArray> signature_tables =
+ factory->NewFixedArray(function_table_count, TENURED);
+ for (int i = 0; i < function_table_count; ++i) {
+ temp_instance.function_tables[i] = factory->NewFixedArray(1, TENURED);
+ temp_instance.signature_tables[i] = factory->NewFixedArray(1, TENURED);
+ function_tables->set(i, *temp_instance.function_tables[i]);
+ signature_tables->set(i, *temp_instance.signature_tables[i]);
+ }
+
+ HistogramTimerScope wasm_compile_module_time_scope(
+ isolate_->counters()->wasm_compile_module_time());
+
+ ModuleBytesEnv module_env(module_, &temp_instance, wire_bytes);
+
+ // The {code_table} array contains import wrappers and functions (which
+ // are both included in {functions.size()}, and export wrappers.
+ int code_table_size = static_cast<int>(module_->functions.size() +
+ module_->num_exported_functions);
+ Handle<FixedArray> code_table =
+ factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
+
+ // Initialize the code table with the illegal builtin. All call sites will
+ // be
+ // patched at instantiation.
+ Handle<Code> illegal_builtin = isolate_->builtins()->Illegal();
+ for (uint32_t i = 0; i < module_->functions.size(); ++i) {
+ code_table->set(static_cast<int>(i), *illegal_builtin);
+ temp_instance.function_code[i] = illegal_builtin;
+ }
+
+ isolate_->counters()->wasm_functions_per_module()->AddSample(
+ static_cast<int>(module_->functions.size()));
+ CompilationHelper helper(isolate_, module_);
+ if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
+ // Avoid a race condition by collecting results into a second vector.
+ std::vector<Handle<Code>> results(temp_instance.function_code);
+ helper.CompileInParallel(&module_env, results, thrower);
+ temp_instance.function_code.swap(results);
+ } else {
+ helper.CompileSequentially(&module_env, temp_instance.function_code,
+ thrower);
+ }
+ if (thrower->error()) return {};
+
+ // At this point, compilation has completed. Update the code table.
+ for (size_t i = FLAG_skip_compiling_wasm_funcs;
+ i < temp_instance.function_code.size(); ++i) {
+ Code* code = *temp_instance.function_code[i];
+ code_table->set(static_cast<int>(i), code);
+ RecordStats(isolate_, code);
+ }
+
+ // Create heap objects for script, module bytes and asm.js offset table to
+ // be
+ // stored in the shared module data.
+ Handle<Script> script;
+ Handle<ByteArray> asm_js_offset_table;
+ if (asm_js_script.is_null()) {
+ script = CreateWasmScript(isolate_, wire_bytes);
+ } else {
+ script = asm_js_script;
+ asm_js_offset_table =
+ isolate_->factory()->NewByteArray(asm_js_offset_table_bytes.length());
+ asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
+ asm_js_offset_table_bytes.length());
+ }
+ // TODO(wasm): only save the sections necessary to deserialize a
+ // {WasmModule}. E.g. function bodies could be omitted.
+ Handle<String> module_bytes =
+ factory
+ ->NewStringFromOneByte({wire_bytes.start(), wire_bytes.length()},
+ TENURED)
+ .ToHandleChecked();
+ DCHECK(module_bytes->IsSeqOneByteString());
+
+ // Create the shared module data.
+ // TODO(clemensh): For the same module (same bytes / same hash), we should
+ // only have one WasmSharedModuleData. Otherwise, we might only set
+ // breakpoints on a (potentially empty) subset of the instances.
+
+ Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
+ isolate_, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes),
+ script, asm_js_offset_table);
+
+ // Create the compiled module object, and populate with compiled functions
+ // and information needed at instantiation time. This object needs to be
+ // serializable. Instantiation may occur off a deserialized version of this
+ // object.
+ Handle<WasmCompiledModule> compiled_module =
+ WasmCompiledModule::New(isolate_, shared);
+ compiled_module->set_num_imported_functions(
+ module_->num_imported_functions);
+ compiled_module->set_code_table(code_table);
+ compiled_module->set_min_mem_pages(module_->min_mem_pages);
+ compiled_module->set_max_mem_pages(module_->max_mem_pages);
+ if (function_table_count > 0) {
+ compiled_module->set_function_tables(function_tables);
+ compiled_module->set_signature_tables(signature_tables);
+ compiled_module->set_empty_function_tables(function_tables);
+ }
+
+ // If we created a wasm script, finish it now and make it public to the
+ // debugger.
+ if (asm_js_script.is_null()) {
+ script->set_wasm_compiled_module(*compiled_module);
+ isolate_->debug()->OnAfterCompile(script);
+ }
+
+ // Compile JS->WASM wrappers for exported functions.
+ JSToWasmWrapperCache js_to_wasm_cache;
+ int func_index = 0;
+ for (auto exp : module_->export_table) {
+ if (exp.kind != kExternalFunction) continue;
+ Handle<Code> wasm_code(Code::cast(code_table->get(exp.index)), isolate_);
+ Handle<Code> wrapper_code =
+ js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(isolate_, module_,
+ wasm_code, exp.index);
+ int export_index =
+ static_cast<int>(module_->functions.size() + func_index);
+ code_table->set(export_index, *wrapper_code);
+ RecordStats(isolate_, *wrapper_code);
+ func_index++;
+ }
-void CompileSequentially(Isolate* isolate, ModuleBytesEnv* module_env,
- std::vector<Handle<Code>>& functions,
- ErrorThrower* thrower) {
- DCHECK(!thrower->error());
-
- const WasmModule* module = module_env->module_env.module;
- for (uint32_t i = FLAG_skip_compiling_wasm_funcs;
- i < module->functions.size(); ++i) {
- const WasmFunction& func = module->functions[i];
- if (func.imported) continue; // Imports are compiled at instantiation time.
-
- Handle<Code> code = Handle<Code>::null();
- // Compile the function.
- code = compiler::WasmCompilationUnit::CompileWasmFunction(
- thrower, isolate, module_env, &func);
- if (code.is_null()) {
- WasmName str = module_env->wire_bytes.GetName(&func);
- thrower->CompileError("Compilation of #%d:%.*s failed.", i, str.length(),
- str.start());
- break;
- }
- // Install the code into the linker table.
- functions[i] = code;
- }
+ return WasmModuleObject::New(isolate_, compiled_module);
}
+};
static void ResetCompiledModule(Isolate* isolate, WasmInstanceObject* owner,
WasmCompiledModule* compiled_module) {
@@ -544,78 +737,6 @@ std::pair<int, int> GetFunctionOffsetAndLength(
return {static_cast<int>(func.code_start_offset),
static_cast<int>(func.code_end_offset - func.code_start_offset)};
}
-
-Handle<Script> CreateWasmScript(Isolate* isolate,
- const ModuleWireBytes& wire_bytes) {
- Handle<Script> script =
- isolate->factory()->NewScript(isolate->factory()->empty_string());
- FixedArray* array = isolate->native_context()->embedder_data();
- script->set_context_data(array->get(v8::Context::kDebugIdIndex));
- script->set_type(Script::TYPE_WASM);
-
- int hash = StringHasher::HashSequentialString(
- reinterpret_cast<const char*>(wire_bytes.start()), wire_bytes.length(),
- kZeroHashSeed);
-
- const int kBufferSize = 50;
- char buffer[kBufferSize];
- int url_chars = SNPrintF(ArrayVector(buffer), "wasm://wasm/%08x", hash);
- DCHECK(url_chars >= 0 && url_chars < kBufferSize);
- MaybeHandle<String> url_str = isolate->factory()->NewStringFromOneByte(
- Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), url_chars),
- TENURED);
- script->set_source_url(*url_str.ToHandleChecked());
-
- int name_chars = SNPrintF(ArrayVector(buffer), "wasm-%08x", hash);
- DCHECK(name_chars >= 0 && name_chars < kBufferSize);
- MaybeHandle<String> name_str = isolate->factory()->NewStringFromOneByte(
- Vector<const uint8_t>(reinterpret_cast<uint8_t*>(buffer), name_chars),
- TENURED);
- script->set_name(*name_str.ToHandleChecked());
-
- return script;
-}
-
-class JSToWasmWrapperCache {
- public:
- Handle<Code> CloneOrCompileJSToWasmWrapper(Isolate* isolate,
- const wasm::WasmModule* module,
- Handle<Code> wasm_code,
- uint32_t index) {
- const wasm::WasmFunction* func = &module->functions[index];
- int cached_idx = sig_map_.Find(func->sig);
- if (cached_idx >= 0) {
- Handle<Code> code = isolate->factory()->CopyCode(code_cache_[cached_idx]);
- // Now patch the call to wasm code.
- for (RelocIterator it(*code, RelocInfo::kCodeTargetMask);; it.next()) {
- DCHECK(!it.done());
- Code* target =
- Code::GetCodeFromTargetAddress(it.rinfo()->target_address());
- if (target->kind() == Code::WASM_FUNCTION ||
- target->kind() == Code::WASM_TO_JS_FUNCTION ||
- target->builtin_index() == Builtins::kIllegal) {
- it.rinfo()->set_target_address(wasm_code->instruction_start());
- break;
- }
- }
- return code;
- }
-
- Handle<Code> code =
- compiler::CompileJSToWasmWrapper(isolate, module, wasm_code, index);
- uint32_t new_cache_idx = sig_map_.FindOrInsert(func->sig);
- DCHECK_EQ(code_cache_.size(), new_cache_idx);
- USE(new_cache_idx);
- code_cache_.push_back(code);
- return code;
- }
-
- private:
- // sig_map_ maps signatures to an index in code_cache_.
- wasm::SignatureMap sig_map_;
- std::vector<Handle<Code>> code_cache_;
-};
-
} // namespace
Handle<JSArrayBuffer> SetupArrayBuffer(Isolate* isolate, void* backing_store,
@@ -723,146 +844,6 @@ int wasm::GetFunctionCodeOffset(Handle<WasmCompiledModule> compiled_module,
WasmModule::WasmModule(Zone* owned)
: owned_zone(owned), pending_tasks(new base::Semaphore(0)) {}
-MaybeHandle<WasmModuleObject> CompileToModuleObject(
- Isolate* isolate, WasmModule* m, ErrorThrower* thrower,
- const ModuleWireBytes& wire_bytes, Handle<Script> asm_js_script,
- Vector<const byte> asm_js_offset_table_bytes) {
- Factory* factory = isolate->factory();
- MaybeHandle<WasmModuleObject> nothing;
- // The {module_wrapper} will take ownership of the {WasmModule} object,
- // and it will be destroyed when the GC reclaims the wrapper object.
- Handle<WasmModuleWrapper> module_wrapper = WasmModuleWrapper::New(isolate, m);
- WasmInstance temp_instance(m);
- temp_instance.context = isolate->native_context();
- temp_instance.mem_size = WasmModule::kPageSize * m->min_mem_pages;
- temp_instance.mem_start = nullptr;
- temp_instance.globals_start = nullptr;
-
- // Initialize the indirect tables with placeholders.
- int function_table_count = static_cast<int>(m->function_tables.size());
- Handle<FixedArray> function_tables =
- factory->NewFixedArray(function_table_count, TENURED);
- Handle<FixedArray> signature_tables =
- factory->NewFixedArray(function_table_count, TENURED);
- for (int i = 0; i < function_table_count; ++i) {
- temp_instance.function_tables[i] = factory->NewFixedArray(1, TENURED);
- temp_instance.signature_tables[i] = factory->NewFixedArray(1, TENURED);
- function_tables->set(i, *temp_instance.function_tables[i]);
- signature_tables->set(i, *temp_instance.signature_tables[i]);
- }
-
- HistogramTimerScope wasm_compile_module_time_scope(
- isolate->counters()->wasm_compile_module_time());
-
- ModuleBytesEnv module_env(m, &temp_instance, wire_bytes);
-
- // The {code_table} array contains import wrappers and functions (which
- // are both included in {functions.size()}, and export wrappers.
- int code_table_size =
- static_cast<int>(m->functions.size() + m->num_exported_functions);
- Handle<FixedArray> code_table =
- factory->NewFixedArray(static_cast<int>(code_table_size), TENURED);
-
- // Initialize the code table with the illegal builtin. All call sites will be
- // patched at instantiation.
- Handle<Code> illegal_builtin = isolate->builtins()->Illegal();
- for (uint32_t i = 0; i < m->functions.size(); ++i) {
- code_table->set(static_cast<int>(i), *illegal_builtin);
- temp_instance.function_code[i] = illegal_builtin;
- }
-
- isolate->counters()->wasm_functions_per_module()->AddSample(
- static_cast<int>(m->functions.size()));
- if (!FLAG_trace_wasm_decoder && FLAG_wasm_num_compilation_tasks != 0) {
- // Avoid a race condition by collecting results into a second vector.
- std::vector<Handle<Code>> results(temp_instance.function_code);
- CompileInParallel(isolate, &module_env, results, thrower);
- temp_instance.function_code.swap(results);
- } else {
- CompileSequentially(isolate, &module_env, temp_instance.function_code,
- thrower);
- }
- if (thrower->error()) return nothing;
-
- // At this point, compilation has completed. Update the code table.
- for (size_t i = FLAG_skip_compiling_wasm_funcs;
- i < temp_instance.function_code.size(); ++i) {
- Code* code = *temp_instance.function_code[i];
- code_table->set(static_cast<int>(i), code);
- RecordStats(isolate, code);
- }
-
- // Create heap objects for script, module bytes and asm.js offset table to be
- // stored in the shared module data.
- Handle<Script> script;
- Handle<ByteArray> asm_js_offset_table;
- if (asm_js_script.is_null()) {
- script = CreateWasmScript(isolate, wire_bytes);
- } else {
- script = asm_js_script;
- asm_js_offset_table =
- isolate->factory()->NewByteArray(asm_js_offset_table_bytes.length());
- asm_js_offset_table->copy_in(0, asm_js_offset_table_bytes.start(),
- asm_js_offset_table_bytes.length());
- }
- // TODO(wasm): only save the sections necessary to deserialize a
- // {WasmModule}. E.g. function bodies could be omitted.
- Handle<String> module_bytes =
- factory
- ->NewStringFromOneByte({wire_bytes.start(), wire_bytes.length()},
- TENURED)
- .ToHandleChecked();
- DCHECK(module_bytes->IsSeqOneByteString());
-
- // Create the shared module data.
- // TODO(clemensh): For the same module (same bytes / same hash), we should
- // only have one WasmSharedModuleData. Otherwise, we might only set
- // breakpoints on a (potentially empty) subset of the instances.
-
- Handle<WasmSharedModuleData> shared = WasmSharedModuleData::New(
- isolate, module_wrapper, Handle<SeqOneByteString>::cast(module_bytes),
- script, asm_js_offset_table);
-
- // Create the compiled module object, and populate with compiled functions
- // and information needed at instantiation time. This object needs to be
- // serializable. Instantiation may occur off a deserialized version of this
- // object.
- Handle<WasmCompiledModule> compiled_module =
- WasmCompiledModule::New(isolate, shared);
- compiled_module->set_num_imported_functions(m->num_imported_functions);
- compiled_module->set_code_table(code_table);
- compiled_module->set_min_mem_pages(m->min_mem_pages);
- compiled_module->set_max_mem_pages(m->max_mem_pages);
- if (function_table_count > 0) {
- compiled_module->set_function_tables(function_tables);
- compiled_module->set_signature_tables(signature_tables);
- compiled_module->set_empty_function_tables(function_tables);
- }
-
- // If we created a wasm script, finish it now and make it public to the
- // debugger.
- if (asm_js_script.is_null()) {
- script->set_wasm_compiled_module(*compiled_module);
- isolate->debug()->OnAfterCompile(script);
- }
-
- // Compile JS->WASM wrappers for exported functions.
- JSToWasmWrapperCache js_to_wasm_cache;
- int func_index = 0;
- for (auto exp : m->export_table) {
- if (exp.kind != kExternalFunction) continue;
- Handle<Code> wasm_code(Code::cast(code_table->get(exp.index)), isolate);
- Handle<Code> wrapper_code = js_to_wasm_cache.CloneOrCompileJSToWasmWrapper(
- isolate, m, wasm_code, exp.index);
- int export_index = static_cast<int>(m->functions.size() + func_index);
- code_table->set(export_index, *wrapper_code);
- RecordStats(isolate, *wrapper_code);
- func_index++;
- }
-
- return WasmModuleObject::New(isolate, compiled_module);
-}
-
static WasmFunction* GetWasmFunctionForImportWrapper(Isolate* isolate,
Handle<Object> target) {
if (target->IsJSFunction()) {
@@ -982,14 +963,12 @@ class InstantiationHelper {
// Build an instance, in all of its glory.
MaybeHandle<WasmInstanceObject> Build() {
- MaybeHandle<WasmInstanceObject> nothing;
-
// Check that an imports argument was provided, if the module requires it.
// No point in continuing otherwise.
if (!module_->import_table.empty() && ffi_.is_null()) {
thrower_->TypeError(
"Imports argument must be present and must be an object");
- return nothing;
+ return {};
}
HistogramTimerScope wasm_instantiate_module_time_scope(
@@ -1086,7 +1065,7 @@ class InstantiationHelper {
globals_ = global_buffer;
if (globals_.is_null()) {
thrower_->RangeError("Out of memory: wasm globals");
- return nothing;
+ return {};
}
Address old_globals_start = nullptr;
if (!owner.is_null()) {
@@ -1116,7 +1095,7 @@ class InstantiationHelper {
// Process the imports for the module.
//--------------------------------------------------------------------------
int num_imported_functions = ProcessImports(code_table, instance);
- if (num_imported_functions < 0) return nothing;
+ if (num_imported_functions < 0) return {};
//--------------------------------------------------------------------------
// Process the initialization for the module's globals.
@@ -1145,7 +1124,7 @@ class InstantiationHelper {
memory_->has_guard_region());
} else if (min_mem_pages > 0) {
memory_ = AllocateMemory(min_mem_pages);
- if (memory_.is_null()) return nothing; // failed to allocate memory
+ if (memory_.is_null()) return {}; // failed to allocate memory
}
//--------------------------------------------------------------------------
@@ -1159,7 +1138,7 @@ class InstantiationHelper {
if (!in_bounds(base, static_cast<uint32_t>(table_init.entries.size()),
table_size)) {
thrower_->LinkError("table initializer is out of bounds");
- return nothing;
+ return {};
}
}
@@ -1172,7 +1151,7 @@ class InstantiationHelper {
? 0 : static_cast<uint32_t>(memory_->byte_length()->Number());
if (!in_bounds(base, seg.source_size, mem_size)) {
thrower_->LinkError("data segment is out of bounds");
- return nothing;
+ return {};
}
}
@@ -1340,7 +1319,7 @@ class InstantiationHelper {
// chain. However, we need to set up everything before executing the
// start function, such that stack trace information can be generated
// correctly already in the start function.
- return nothing;
+ return {};
}
}
@@ -2613,7 +2592,6 @@ MaybeHandle<WasmModuleObject> wasm::SyncCompileTranslatedAsmJs(
Isolate* isolate, ErrorThrower* thrower, const ModuleWireBytes& bytes,
Handle<Script> asm_js_script,
Vector<const byte> asm_js_offset_table_bytes) {
- MaybeHandle<WasmModuleObject> nothing;
ModuleResult result = DecodeWasmModule(isolate, bytes.start(), bytes.end(),
false, kAsmJsOrigin);
@@ -2621,22 +2599,20 @@ MaybeHandle<WasmModuleObject> wasm::SyncCompileTranslatedAsmJs(
// TODO(titzer): use Result<std::unique_ptr<const WasmModule*>>?
if (result.val) delete result.val;
thrower->CompileFailed("Wasm decoding failed", result);
- return nothing;
+ return {};
}
- return CompileToModuleObject(isolate, const_cast<WasmModule*>(result.val),
- thrower, bytes, asm_js_script,
- asm_js_offset_table_bytes);
+ CompilationHelper helper(isolate, const_cast<WasmModule*>(result.val));
+ return helper.CompileToModuleObject(thrower, bytes, asm_js_script,
+ asm_js_offset_table_bytes);
}
MaybeHandle<WasmModuleObject> wasm::SyncCompile(Isolate* isolate,
ErrorThrower* thrower,
const ModuleWireBytes& bytes) {
- MaybeHandle<WasmModuleObject> nothing;
-
if (!IsWasmCodegenAllowed(isolate, isolate->native_context())) {
thrower->CompileError("Wasm code generation disallowed in this context");
- return nothing;
+ return {};
}
ModuleResult result =
@@ -2644,12 +2620,12 @@ MaybeHandle<WasmModuleObject> wasm::SyncCompile(Isolate* isolate,
if (result.failed()) {
if (result.val) delete result.val;
thrower->CompileFailed("Wasm decoding failed", result);
- return nothing;
+ return {};
}
- return CompileToModuleObject(isolate, const_cast<WasmModule*>(result.val),
- thrower, bytes, Handle<Script>(),
- Vector<const byte>());
+ CompilationHelper helper(isolate, const_cast<WasmModule*>(result.val));
+ return helper.CompileToModuleObject(thrower, bytes, Handle<Script>(),
+ Vector<const byte>());
}
MaybeHandle<WasmInstanceObject> wasm::SyncInstantiate(
« no previous file with comments | « src/compiler/wasm-compiler.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698