[wasm] Restore eager parallel export-wrapper compilation

As part of moving export wrappers to the isolate, it was tried to
compile them lazily on the main thread. This resulted in large
slowdowns in some cases, therefore we restore the eager parallel
compilation.

Bug: chromium:1365726
Change-Id: I9cc8d5728f3a5c71099f0e0fdcc605b37d4d6618
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3905193
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83339}
This commit is contained in:
Manos Koukoutos 2022-09-20 14:55:31 +02:00 committed by V8 LUCI CQ
parent 67106ff494
commit 2e8d8f8f86
3 changed files with 126 additions and 2 deletions

View File

@ -616,6 +616,7 @@ class CompilationStateImpl {
std::shared_ptr<JSToWasmWrapperCompilationUnit>
GetNextJSToWasmWrapperCompilationUnit();
void FinalizeJSToWasmWrappers(Isolate* isolate, const WasmModule* module);
void OnFinishedUnits(base::Vector<WasmCode*>);
void OnFinishedJSToWasmWrapperUnits(int num);
@ -1509,6 +1510,13 @@ void TierUpNowForTesting(Isolate* isolate, WasmInstanceObject instance,
namespace {
void RecordStats(CodeT codet, Counters* counters) {
if (codet.is_off_heap_trampoline()) return;
Code code = FromCodeT(codet);
counters->wasm_generated_code_size()->Increment(code.raw_body_size());
counters->wasm_reloc_size()->Increment(code.relocation_info().length());
}
enum CompilationExecutionResult : int8_t { kNoMoreUnits, kYield };
CompilationExecutionResult ExecuteJSToWasmWrapperCompilationUnits(
@ -1932,6 +1940,8 @@ void CompileNativeModule(Isolate* isolate,
return;
}
compilation_state->FinalizeJSToWasmWrappers(isolate, native_module->module());
compilation_state->WaitForCompilationEvent(
CompilationEvent::kFinishedBaselineCompilation);
@ -1994,6 +2004,7 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
std::shared_ptr<NativeModule> native_module = engine->MaybeGetNativeModule(
wasm_module->origin, wire_bytes_copy.as_vector(), isolate);
if (native_module) {
CompileJsToWasmWrappers(isolate, wasm_module);
return native_module;
}
@ -2028,6 +2039,7 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
if (thrower->error()) return {};
if (cache_hit) {
CompileJsToWasmWrappers(isolate, wasm_module);
return native_module;
}
@ -2303,6 +2315,17 @@ void AsyncCompileJob::FinishCompile(bool is_after_cache_hit) {
isolate_->debug()->OnAfterCompile(script);
}
// TODO(bbudge) Allow deserialization without wrapper compilation, so we can
// just compile wrappers here.
if (!is_after_deserialization) {
if (is_after_cache_hit) {
// TODO(thibaudm): Look into sharing wrappers.
CompileJsToWasmWrappers(isolate_, module);
} else {
compilation_state->FinalizeJSToWasmWrappers(isolate_, module);
}
}
// We can only update the feature counts once the entire compile is done.
compilation_state->PublishDetectedFeatures(isolate_);
@ -3524,6 +3547,30 @@ CompilationStateImpl::GetNextJSToWasmWrapperCompilationUnit() {
return js_to_wasm_wrapper_units_[outstanding_units - 1];
}
void CompilationStateImpl::FinalizeJSToWasmWrappers(Isolate* isolate,
const WasmModule* module) {
// TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
// optimization we create a code memory modification scope that avoids
// changing the page permissions back-and-forth between RWX and RX, because
// many such wrapper are allocated in sequence below.
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
"wasm.FinalizeJSToWasmWrappers", "wrappers",
js_to_wasm_wrapper_units_.size());
isolate->heap()->EnsureWasmCanonicalRttsSize(module->MaxCanonicalTypeIndex() +
1);
CodePageCollectionMemoryModificationScope modification_scope(isolate->heap());
for (auto& unit : js_to_wasm_wrapper_units_) {
DCHECK_EQ(isolate, unit->isolate());
Handle<CodeT> code = unit->Finalize();
uint32_t index =
GetExportWrapperIndex(unit->canonical_sig_index(), unit->is_import());
isolate->heap()->js_to_wasm_wrappers().Set(index,
MaybeObject::FromObject(*code));
RecordStats(*code, isolate->counters());
}
}
CompilationUnitQueues::Queue* CompilationStateImpl::GetQueueForCompileTask(
int task_id) {
return compilation_unit_queues_.GetQueueForTask(task_id);
@ -3898,6 +3945,78 @@ class CompileJSToWasmWrapperJob final : public JobTask {
};
} // namespace
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module) {
TRACE_EVENT0("v8.wasm", "wasm.CompileJsToWasmWrappers");
isolate->heap()->EnsureWasmCanonicalRttsSize(module->MaxCanonicalTypeIndex() +
1);
JSToWasmWrapperQueue queue;
JSToWasmWrapperUnitMap compilation_units;
WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate);
// Prepare compilation units in the main thread.
for (auto exp : module->export_table) {
if (exp.kind != kExternalFunction) continue;
auto& function = module->functions[exp.index];
uint32_t canonical_type_index =
module->isorecursive_canonical_type_ids[function.sig_index];
int wrapper_index =
GetExportWrapperIndex(canonical_type_index, function.imported);
auto existing_wrapper =
isolate->heap()->js_to_wasm_wrappers().Get(wrapper_index);
if (existing_wrapper.IsStrongOrWeak() &&
!existing_wrapper.GetHeapObject().IsUndefined()) {
continue;
}
JSToWasmWrapperKey key(function.imported, canonical_type_index);
if (queue.insert(key, nullptr)) {
auto unit = std::make_unique<JSToWasmWrapperCompilationUnit>(
isolate, function.sig, canonical_type_index, module,
function.imported, enabled_features,
JSToWasmWrapperCompilationUnit::kAllowGeneric);
compilation_units.emplace(key, std::move(unit));
}
}
{
// This is nested inside the event above, so the name can be less
// descriptive. It's mainly to log the number of wrappers.
TRACE_EVENT1("v8.wasm", "wasm.JsToWasmWrapperCompilation", "num_wrappers",
compilation_units.size());
auto job =
std::make_unique<CompileJSToWasmWrapperJob>(&queue, &compilation_units);
if (v8_flags.wasm_num_compilation_tasks > 0) {
auto job_handle = V8::GetCurrentPlatform()->CreateJob(
TaskPriority::kUserVisible, std::move(job));
// Wait for completion, while contributing to the work.
job_handle->Join();
} else {
job->Run(nullptr);
}
}
// Finalize compilation jobs in the main thread.
// TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
// optimization we create a code memory modification scope that avoids
// changing the page permissions back-and-forth between RWX and RX, because
// many such wrapper are allocated in sequence below.
CodePageCollectionMemoryModificationScope modification_scope(isolate->heap());
for (auto& pair : compilation_units) {
JSToWasmWrapperKey key = pair.first;
JSToWasmWrapperCompilationUnit* unit = pair.second.get();
DCHECK_EQ(isolate, unit->isolate());
Handle<CodeT> code = unit->Finalize();
int wrapper_index = GetExportWrapperIndex(key.second, key.first);
isolate->heap()->js_to_wasm_wrappers().Set(
wrapper_index, HeapObjectReference::Strong(*code));
RecordStats(*code, isolate->counters());
}
}
WasmCode* CompileImportWrapper(
NativeModule* native_module, Counters* counters,
compiler::WasmImportCallKind kind, const FunctionSig* sig,

View File

@ -62,6 +62,9 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
void RecompileNativeModule(NativeModule* native_module,
TieringState new_tiering_state);
V8_EXPORT_PRIVATE
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module);
// Compiles the wrapper for this (kind, sig) pair and sets the corresponding
// cache entry. Assumes the key already exists in the cache but has not been
// compiled yet.

View File

@ -1370,9 +1370,11 @@ WasmInstanceObject::GetOrCreateWasmInternalFunction(
wrapper = wasm::JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
isolate, function.sig, canonical_sig_index, instance->module(),
function.imported);
isolate->heap()->js_to_wasm_wrappers().Set(
wrapper_index, HeapObjectReference::Weak(*wrapper));
}
// Store the wrapper in the isolate, or make its reference weak now that we
// have a function referencing it.
isolate->heap()->js_to_wasm_wrappers().Set(
wrapper_index, HeapObjectReference::Weak(*wrapper));
auto external = Handle<WasmExternalFunction>::cast(WasmExportedFunction::New(
isolate, instance, function_index,
static_cast<int>(function.sig->parameter_count()), wrapper));