Commit b15b2c91 authored by Thibaud Michaud's avatar Thibaud Michaud Committed by Commit Bot

[wasm] Early compilation of import wrappers

Compile import wrappers during module compilation by introducing import
wrapper compilation units, the goal being to reduce instantiation time.

For each wrapper, we assume the imported function is going to be a
kJSFunctionArityMatchSloppy at instantiation time, which should be the
most common case. If the function turns out to have a different kind the
wrapper is going to be recompiled with the correct kind during instantiation.

R=ahaas@chromium.org, clemensh@chromium.org
CC=titzer@chromium.org

Bug: v8:9231
Change-Id: Ieb050b09d1c19f2a5a3e59132a1864dadb06775d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1630685
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarAndreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61993}
parent fe9d6a49
...@@ -6103,9 +6103,8 @@ wasm::WasmOpcode GetMathIntrinsicOpcode(WasmImportCallKind kind, ...@@ -6103,9 +6103,8 @@ wasm::WasmOpcode GetMathIntrinsicOpcode(WasmImportCallKind kind,
#undef CASE #undef CASE
} }
wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine, wasm::WasmCompilationResult CompileWasmMathIntrinsic(
wasm::NativeModule* native_module, wasm::WasmEngine* wasm_engine, WasmImportCallKind kind,
WasmImportCallKind kind,
wasm::FunctionSig* sig) { wasm::FunctionSig* sig) {
DCHECK_EQ(1, sig->return_count()); DCHECK_EQ(1, sig->return_count());
...@@ -6125,7 +6124,7 @@ wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine, ...@@ -6125,7 +6124,7 @@ wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine,
InstructionSelector::AlignmentRequirements())); InstructionSelector::AlignmentRequirements()));
wasm::CompilationEnv env( wasm::CompilationEnv env(
native_module->module(), wasm::UseTrapHandler::kNoTrapHandler, nullptr, wasm::UseTrapHandler::kNoTrapHandler,
wasm::RuntimeExceptionSupport::kNoRuntimeExceptionSupport, wasm::RuntimeExceptionSupport::kNoRuntimeExceptionSupport,
wasm::kAllWasmFeatures, wasm::LowerSimd::kNoLowerSimd); wasm::kAllWasmFeatures, wasm::LowerSimd::kNoLowerSimd);
...@@ -6167,21 +6166,12 @@ wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine, ...@@ -6167,21 +6166,12 @@ wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine,
wasm_engine, call_descriptor, mcgraph, Code::WASM_FUNCTION, wasm_engine, call_descriptor, mcgraph, Code::WASM_FUNCTION,
wasm::WasmCode::kFunction, debug_name, WasmStubAssemblerOptions(), wasm::WasmCode::kFunction, debug_name, WasmStubAssemblerOptions(),
source_positions); source_positions);
std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode( return result;
wasm::WasmCode::kAnonymousFuncIndex, result.code_desc,
result.frame_slot_count, result.tagged_parameter_slots,
std::move(result.protected_instructions),
std::move(result.source_positions), wasm::WasmCode::kFunction,
wasm::ExecutionTier::kNone);
// TODO(titzer): add counters for math intrinsic code size / allocation
return native_module->PublishCode(std::move(wasm_code));
} }
wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine, wasm::WasmCompilationResult CompileWasmImportCallWrapper(
wasm::NativeModule* native_module, wasm::WasmEngine* wasm_engine, wasm::CompilationEnv* env,
WasmImportCallKind kind, WasmImportCallKind kind, wasm::FunctionSig* sig, bool source_positions) {
wasm::FunctionSig* sig,
bool source_positions) {
DCHECK_NE(WasmImportCallKind::kLinkError, kind); DCHECK_NE(WasmImportCallKind::kLinkError, kind);
DCHECK_NE(WasmImportCallKind::kWasmToWasm, kind); DCHECK_NE(WasmImportCallKind::kWasmToWasm, kind);
...@@ -6189,7 +6179,7 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine, ...@@ -6189,7 +6179,7 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
if (FLAG_wasm_math_intrinsics && if (FLAG_wasm_math_intrinsics &&
kind >= WasmImportCallKind::kFirstMathIntrinsic && kind >= WasmImportCallKind::kFirstMathIntrinsic &&
kind <= WasmImportCallKind::kLastMathIntrinsic) { kind <= WasmImportCallKind::kLastMathIntrinsic) {
return CompileWasmMathIntrinsic(wasm_engine, native_module, kind, sig); return CompileWasmMathIntrinsic(wasm_engine, kind, sig);
} }
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
...@@ -6214,7 +6204,7 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine, ...@@ -6214,7 +6204,7 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
WasmWrapperGraphBuilder builder(&zone, &jsgraph, sig, source_position_table, WasmWrapperGraphBuilder builder(&zone, &jsgraph, sig, source_position_table,
StubCallMode::kCallWasmRuntimeStub, StubCallMode::kCallWasmRuntimeStub,
native_module->enabled_features()); env->enabled_features);
builder.set_control_ptr(&control); builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect); builder.set_effect_ptr(&effect);
builder.BuildWasmImportCallWrapper(kind); builder.BuildWasmImportCallWrapper(kind);
...@@ -6232,13 +6222,8 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine, ...@@ -6232,13 +6222,8 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
wasm_engine, incoming, &jsgraph, Code::WASM_TO_JS_FUNCTION, wasm_engine, incoming, &jsgraph, Code::WASM_TO_JS_FUNCTION,
wasm::WasmCode::kWasmToJsWrapper, func_name, WasmStubAssemblerOptions(), wasm::WasmCode::kWasmToJsWrapper, func_name, WasmStubAssemblerOptions(),
source_position_table); source_position_table);
std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode( result.kind = wasm::WasmCompilationResult::kWasmToJsWrapper;
wasm::WasmCode::kAnonymousFuncIndex, result.code_desc, return result;
result.frame_slot_count, result.tagged_parameter_slots,
std::move(result.protected_instructions),
std::move(result.source_positions), wasm::WasmCode::kWasmToJsWrapper,
wasm::ExecutionTier::kNone);
return native_module->PublishCode(std::move(wasm_code));
} }
wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine, wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine,
...@@ -6290,9 +6275,8 @@ wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine, ...@@ -6290,9 +6275,8 @@ wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine,
wasm::WasmCode::kWasmToCapiWrapper, debug_name, wasm::WasmCode::kWasmToCapiWrapper, debug_name,
WasmStubAssemblerOptions(), source_positions); WasmStubAssemblerOptions(), source_positions);
std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode( std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
wasm::WasmCode::kAnonymousFuncIndex, result.code_desc, wasm::kAnonymousFuncIndex, result.code_desc, result.frame_slot_count,
result.frame_slot_count, result.tagged_parameter_slots, result.tagged_parameter_slots, std::move(result.protected_instructions),
std::move(result.protected_instructions),
std::move(result.source_positions), wasm::WasmCode::kWasmToCapiWrapper, std::move(result.source_positions), wasm::WasmCode::kWasmToCapiWrapper,
wasm::ExecutionTier::kNone); wasm::ExecutionTier::kNone);
return native_module->PublishCode(std::move(wasm_code)); return native_module->PublishCode(std::move(wasm_code));
...@@ -6338,6 +6322,7 @@ wasm::WasmCompilationResult CompileWasmInterpreterEntry( ...@@ -6338,6 +6322,7 @@ wasm::WasmCompilationResult CompileWasmInterpreterEntry(
wasm::WasmCode::kInterpreterEntry, func_name.begin(), wasm::WasmCode::kInterpreterEntry, func_name.begin(),
WasmStubAssemblerOptions()); WasmStubAssemblerOptions());
result.result_tier = wasm::ExecutionTier::kInterpreter; result.result_tier = wasm::ExecutionTier::kInterpreter;
result.kind = wasm::WasmCompilationResult::kInterpreterEntry;
return result; return result;
} }
......
...@@ -103,13 +103,19 @@ enum class WasmImportCallKind : uint8_t { ...@@ -103,13 +103,19 @@ enum class WasmImportCallKind : uint8_t {
kUseCallBuiltin kUseCallBuiltin
}; };
// TODO(wasm): There should be only one import kind for sloppy and strict in
// order to reduce wrapper cache misses. The mode can be checked at runtime
// instead.
constexpr WasmImportCallKind kDefaultImportCallKind =
WasmImportCallKind::kJSFunctionArityMatchSloppy;
V8_EXPORT_PRIVATE WasmImportCallKind V8_EXPORT_PRIVATE WasmImportCallKind
GetWasmImportCallKind(Handle<JSReceiver> callable, wasm::FunctionSig* sig, GetWasmImportCallKind(Handle<JSReceiver> callable, wasm::FunctionSig* sig,
bool has_bigint_feature); bool has_bigint_feature);
// Compiles an import call wrapper, which allows WASM to call imports. // Compiles an import call wrapper, which allows WASM to call imports.
V8_EXPORT_PRIVATE wasm::WasmCode* CompileWasmImportCallWrapper( V8_EXPORT_PRIVATE wasm::WasmCompilationResult CompileWasmImportCallWrapper(
wasm::WasmEngine*, wasm::NativeModule*, WasmImportCallKind, wasm::WasmEngine*, wasm::CompilationEnv* env, WasmImportCallKind,
wasm::FunctionSig*, bool source_positions); wasm::FunctionSig*, bool source_positions);
// Compiles a host call wrapper, which allows WASM to call host functions. // Compiles a host call wrapper, which allows WASM to call host functions.
......
...@@ -113,6 +113,42 @@ ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier( ...@@ -113,6 +113,42 @@ ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier(
} }
WasmCompilationResult WasmCompilationUnit::ExecuteCompilation( WasmCompilationResult WasmCompilationUnit::ExecuteCompilation(
WasmEngine* engine, CompilationEnv* env,
const std::shared_ptr<WireBytesStorage>& wire_bytes_storage,
Counters* counters, WasmFeatures* detected) {
WasmCompilationResult result;
if (func_index_ < static_cast<int>(env->module->num_imported_functions)) {
result = ExecuteImportWrapperCompilation(engine, env);
} else {
result = ExecuteFunctionCompilation(engine, env, wire_bytes_storage,
counters, detected);
}
if (result.succeeded()) {
counters->wasm_generated_code_size()->Increment(
result.code_desc.instr_size);
counters->wasm_reloc_size()->Increment(result.code_desc.reloc_size);
}
result.func_index = func_index_;
result.requested_tier = tier_;
return result;
}
WasmCompilationResult WasmCompilationUnit::ExecuteImportWrapperCompilation(
WasmEngine* engine, CompilationEnv* env) {
FunctionSig* sig = env->module->functions[func_index_].sig;
// Assume the wrapper is going to be a JS function with matching arity at
// instantiation time.
auto kind = compiler::kDefaultImportCallKind;
bool source_positions = env->module->origin == kAsmJsOrigin;
WasmCompilationResult result = compiler::CompileWasmImportCallWrapper(
engine, env, kind, sig, source_positions);
return result;
}
WasmCompilationResult WasmCompilationUnit::ExecuteFunctionCompilation(
WasmEngine* wasm_engine, CompilationEnv* env, WasmEngine* wasm_engine, CompilationEnv* env,
const std::shared_ptr<WireBytesStorage>& wire_bytes_storage, const std::shared_ptr<WireBytesStorage>& wire_bytes_storage,
Counters* counters, WasmFeatures* detected) { Counters* counters, WasmFeatures* detected) {
...@@ -167,15 +203,6 @@ WasmCompilationResult WasmCompilationUnit::ExecuteCompilation( ...@@ -167,15 +203,6 @@ WasmCompilationResult WasmCompilationUnit::ExecuteCompilation(
break; break;
} }
result.func_index = func_index_;
result.requested_tier = tier_;
if (result.succeeded()) {
counters->wasm_generated_code_size()->Increment(
result.code_desc.instr_size);
counters->wasm_reloc_size()->Increment(result.code_desc.reloc_size);
}
return result; return result;
} }
...@@ -190,6 +217,8 @@ void WasmCompilationUnit::CompileWasmFunction(Isolate* isolate, ...@@ -190,6 +217,8 @@ void WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
wire_bytes.start() + function->code.offset(), wire_bytes.start() + function->code.offset(),
wire_bytes.start() + function->code.end_offset()}; wire_bytes.start() + function->code.end_offset()};
DCHECK_LE(native_module->num_imported_functions(), function->func_index);
DCHECK_LT(function->func_index, native_module->num_functions());
WasmCompilationUnit unit(function->func_index, tier); WasmCompilationUnit unit(function->func_index, tier);
CompilationEnv env = native_module->CreateCompilationEnv(); CompilationEnv env = native_module->CreateCompilationEnv();
WasmCompilationResult result = unit.ExecuteCompilation( WasmCompilationResult result = unit.ExecuteCompilation(
......
...@@ -43,6 +43,12 @@ struct WasmCompilationResult { ...@@ -43,6 +43,12 @@ struct WasmCompilationResult {
public: public:
MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmCompilationResult); MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmCompilationResult);
enum Kind : int8_t {
kFunction,
kWasmToJsWrapper,
kInterpreterEntry,
};
bool succeeded() const { return code_desc.buffer != nullptr; } bool succeeded() const { return code_desc.buffer != nullptr; }
bool failed() const { return !succeeded(); } bool failed() const { return !succeeded(); }
operator bool() const { return succeeded(); } operator bool() const { return succeeded(); }
...@@ -53,9 +59,10 @@ struct WasmCompilationResult { ...@@ -53,9 +59,10 @@ struct WasmCompilationResult {
uint32_t tagged_parameter_slots = 0; uint32_t tagged_parameter_slots = 0;
OwnedVector<byte> source_positions; OwnedVector<byte> source_positions;
OwnedVector<trap_handler::ProtectedInstructionData> protected_instructions; OwnedVector<trap_handler::ProtectedInstructionData> protected_instructions;
int func_index; int func_index = static_cast<int>(kAnonymousFuncIndex);
ExecutionTier requested_tier; ExecutionTier requested_tier;
ExecutionTier result_tier; ExecutionTier result_tier;
Kind kind = kFunction;
}; };
class V8_EXPORT_PRIVATE WasmCompilationUnit final { class V8_EXPORT_PRIVATE WasmCompilationUnit final {
...@@ -77,6 +84,14 @@ class V8_EXPORT_PRIVATE WasmCompilationUnit final { ...@@ -77,6 +84,14 @@ class V8_EXPORT_PRIVATE WasmCompilationUnit final {
ExecutionTier); ExecutionTier);
private: private:
WasmCompilationResult ExecuteFunctionCompilation(
WasmEngine* wasm_engine, CompilationEnv* env,
const std::shared_ptr<WireBytesStorage>& wire_bytes_storage,
Counters* counters, WasmFeatures* detected);
WasmCompilationResult ExecuteImportWrapperCompilation(WasmEngine* engine,
CompilationEnv* env);
int func_index_; int func_index_;
ExecutionTier tier_; ExecutionTier tier_;
}; };
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include "src/wasm/wasm-limits.h" #include "src/wasm/wasm-limits.h"
#include "src/wasm/wasm-memory.h" #include "src/wasm/wasm-memory.h"
#include "src/wasm/wasm-objects-inl.h" #include "src/wasm/wasm-objects-inl.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/wasm/wasm-result.h" #include "src/wasm/wasm-result.h"
#include "src/wasm/wasm-serialization.h" #include "src/wasm/wasm-serialization.h"
...@@ -380,7 +381,7 @@ class CompilationStateImpl { ...@@ -380,7 +381,7 @@ class CompilationStateImpl {
// Initialize compilation progress. Set compilation tiers to expect for // Initialize compilation progress. Set compilation tiers to expect for
// baseline and top tier compilation. Must be set before {AddCompilationUnits} // baseline and top tier compilation. Must be set before {AddCompilationUnits}
// is invoked which triggers background compilation. // is invoked which triggers background compilation.
void InitializeCompilationProgress(bool lazy_module); void InitializeCompilationProgress(bool lazy_module, int num_import_wrappers);
// Add the callback function to be called on compilation events. Needs to be // Add the callback function to be called on compilation events. Needs to be
// set before {AddCompilationUnits} is run to ensure that it receives all // set before {AddCompilationUnits} is run to ensure that it receives all
...@@ -409,13 +410,11 @@ class CompilationStateImpl { ...@@ -409,13 +410,11 @@ class CompilationStateImpl {
bool baseline_compilation_finished() const { bool baseline_compilation_finished() const {
base::MutexGuard guard(&callbacks_mutex_); base::MutexGuard guard(&callbacks_mutex_);
DCHECK_LE(outstanding_baseline_functions_, outstanding_top_tier_functions_); return outstanding_baseline_units_ == 0;
return outstanding_baseline_functions_ == 0;
} }
bool top_tier_compilation_finished() const { bool top_tier_compilation_finished() const {
base::MutexGuard guard(&callbacks_mutex_); base::MutexGuard guard(&callbacks_mutex_);
DCHECK_LE(outstanding_baseline_functions_, outstanding_top_tier_functions_);
return outstanding_top_tier_functions_ == 0; return outstanding_top_tier_functions_ == 0;
} }
...@@ -517,7 +516,7 @@ class CompilationStateImpl { ...@@ -517,7 +516,7 @@ class CompilationStateImpl {
// Callback functions to be called on compilation events. // Callback functions to be called on compilation events.
std::vector<CompilationState::callback_t> callbacks_; std::vector<CompilationState::callback_t> callbacks_;
int outstanding_baseline_functions_ = 0; int outstanding_baseline_units_ = 0;
int outstanding_top_tier_functions_ = 0; int outstanding_top_tier_functions_ = 0;
std::vector<uint8_t> compilation_progress_; std::vector<uint8_t> compilation_progress_;
...@@ -699,6 +698,10 @@ class CompilationUnitBuilder { ...@@ -699,6 +698,10 @@ class CompilationUnitBuilder {
native_module->module())) {} native_module->module())) {}
void AddUnits(uint32_t func_index) { void AddUnits(uint32_t func_index) {
if (func_index < native_module_->module()->num_imported_functions) {
baseline_units_.emplace_back(func_index, ExecutionTier::kNone);
return;
}
ExecutionTierPair tiers = GetRequestedExecutionTiers( ExecutionTierPair tiers = GetRequestedExecutionTiers(
native_module_->module(), compilation_state()->compile_mode(), native_module_->module(), compilation_state()->compile_mode(),
native_module_->enabled_features(), func_index); native_module_->enabled_features(), func_index);
...@@ -846,6 +849,8 @@ bool CompileLazy(Isolate* isolate, NativeModule* native_module, ...@@ -846,6 +849,8 @@ bool CompileLazy(Isolate* isolate, NativeModule* native_module,
ExecutionTierPair tiers = GetRequestedExecutionTiers( ExecutionTierPair tiers = GetRequestedExecutionTiers(
module, compilation_state->compile_mode(), enabled_features, func_index); module, compilation_state->compile_mode(), enabled_features, func_index);
DCHECK_LE(native_module->num_imported_functions(), func_index);
DCHECK_LT(func_index, native_module->num_functions());
WasmCompilationUnit baseline_unit(func_index, tiers.baseline_tier); WasmCompilationUnit baseline_unit(func_index, tiers.baseline_tier);
CompilationEnv env = native_module->CreateCompilationEnv(); CompilationEnv env = native_module->CreateCompilationEnv();
WasmCompilationResult result = baseline_unit.ExecuteCompilation( WasmCompilationResult result = baseline_unit.ExecuteCompilation(
...@@ -970,6 +975,29 @@ bool ExecuteCompilationUnits( ...@@ -970,6 +975,29 @@ bool ExecuteCompilationUnits(
std::vector<WasmCode*> code_vector = std::vector<WasmCode*> code_vector =
compile_scope->native_module()->AddCompiledCode( compile_scope->native_module()->AddCompiledCode(
VectorOf(results_to_publish)); VectorOf(results_to_publish));
// For import wrapper compilation units, add result to the cache.
const NativeModule* native_module = compile_scope->native_module();
int num_imported_functions = native_module->num_imported_functions();
DCHECK_EQ(code_vector.size(), results_to_publish.size());
WasmImportWrapperCache* cache = native_module->import_wrapper_cache();
for (WasmCode* code : code_vector) {
int func_index = code->index();
DCHECK_LE(0, func_index);
DCHECK_LT(func_index, native_module->num_functions());
if (func_index < num_imported_functions) {
FunctionSig* sig = native_module->module()->functions[func_index].sig;
WasmImportWrapperCache::CacheKey key(compiler::kDefaultImportCallKind,
sig);
// If two imported functions have the same key, only one of them should
// have been added as a compilation unit. So it is always the first time
// we compile a wrapper for this key here.
DCHECK_NULL((*cache)[key]);
(*cache)[key] = code;
code->IncRef();
}
}
compile_scope->compilation_state()->OnFinishedUnits(VectorOf(code_vector)); compile_scope->compilation_state()->OnFinishedUnits(VectorOf(code_vector));
results_to_publish.clear(); results_to_publish.clear();
}; };
...@@ -1021,15 +1049,41 @@ bool ExecuteCompilationUnits( ...@@ -1021,15 +1049,41 @@ bool ExecuteCompilationUnits(
return true; return true;
} }
namespace {
// Returns the number of units added.
int AddImportWrapperUnits(NativeModule* native_module,
CompilationUnitBuilder* builder) {
std::unordered_set<WasmImportWrapperCache::CacheKey,
WasmImportWrapperCache::CacheKeyHash>
keys;
int num_imported_functions = native_module->num_imported_functions();
for (int func_index = 0; func_index < num_imported_functions; func_index++) {
FunctionSig* sig = native_module->module()->functions[func_index].sig;
bool has_bigint_feature = native_module->enabled_features().bigint;
if (!IsJSCompatibleSignature(sig, has_bigint_feature)) {
continue;
}
WasmImportWrapperCache::CacheKey key(compiler::kDefaultImportCallKind, sig);
auto it = keys.insert(key);
if (it.second) {
// Ensure that all keys exist in the cache, so that we can populate the
// cache later without locking.
(*native_module->import_wrapper_cache())[key] = nullptr;
builder->AddUnits(func_index);
}
}
return static_cast<int>(keys.size());
}
} // namespace
void InitializeCompilationUnits(NativeModule* native_module) { void InitializeCompilationUnits(NativeModule* native_module) {
CompilationStateImpl* compilation_state = CompilationStateImpl* compilation_state =
Impl(native_module->compilation_state()); Impl(native_module->compilation_state());
const bool lazy_module = IsLazyModule(native_module->module()); const bool lazy_module = IsLazyModule(native_module->module());
compilation_state->InitializeCompilationProgress(lazy_module);
ModuleWireBytes wire_bytes(native_module->wire_bytes()); ModuleWireBytes wire_bytes(native_module->wire_bytes());
CompilationUnitBuilder builder(native_module); CompilationUnitBuilder builder(native_module);
auto* module = native_module->module(); auto* module = native_module->module();
uint32_t start = module->num_imported_functions; uint32_t start = module->num_imported_functions;
uint32_t end = start + module->num_declared_functions; uint32_t end = start + module->num_declared_functions;
for (uint32_t func_index = start; func_index < end; func_index++) { for (uint32_t func_index = start; func_index < end; func_index++) {
...@@ -1045,6 +1099,9 @@ void InitializeCompilationUnits(NativeModule* native_module) { ...@@ -1045,6 +1099,9 @@ void InitializeCompilationUnits(NativeModule* native_module) {
builder.AddUnits(func_index); builder.AddUnits(func_index);
} }
} }
int num_import_wrappers = AddImportWrapperUnits(native_module, &builder);
compilation_state->InitializeCompilationProgress(lazy_module,
num_import_wrappers);
builder.Commit(); builder.Commit();
} }
...@@ -1850,13 +1907,19 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader( ...@@ -1850,13 +1907,19 @@ bool AsyncStreamingProcessor::ProcessCodeSectionHeader(
compilation_state->SetWireBytesStorage(std::move(wire_bytes_storage)); compilation_state->SetWireBytesStorage(std::move(wire_bytes_storage));
DCHECK_EQ(job_->native_module_->module()->origin, kWasmOrigin); DCHECK_EQ(job_->native_module_->module()->origin, kWasmOrigin);
const bool lazy_module = job_->wasm_lazy_compilation_; const bool lazy_module = job_->wasm_lazy_compilation_;
compilation_state->InitializeCompilationProgress(lazy_module);
// Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the // Set outstanding_finishers_ to 2, because both the AsyncCompileJob and the
// AsyncStreamingProcessor have to finish. // AsyncStreamingProcessor have to finish.
job_->outstanding_finishers_.store(2); job_->outstanding_finishers_.store(2);
compilation_unit_builder_.reset( compilation_unit_builder_.reset(
new CompilationUnitBuilder(job_->native_module_.get())); new CompilationUnitBuilder(job_->native_module_.get()));
NativeModule* native_module = job_->native_module_.get();
int num_import_wrappers =
AddImportWrapperUnits(native_module, compilation_unit_builder_.get());
compilation_state->InitializeCompilationProgress(lazy_module,
num_import_wrappers);
return true; return true;
} }
...@@ -2022,16 +2085,16 @@ void CompilationStateImpl::AbortCompilation() { ...@@ -2022,16 +2085,16 @@ void CompilationStateImpl::AbortCompilation() {
callbacks_.clear(); callbacks_.clear();
} }
void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module) { void CompilationStateImpl::InitializeCompilationProgress(
bool lazy_module, int num_import_wrappers) {
DCHECK(!failed()); DCHECK(!failed());
auto enabled_features = native_module_->enabled_features(); auto enabled_features = native_module_->enabled_features();
auto* module = native_module_->module(); auto* module = native_module_->module();
base::MutexGuard guard(&callbacks_mutex_); base::MutexGuard guard(&callbacks_mutex_);
DCHECK_EQ(0, outstanding_baseline_functions_); DCHECK_EQ(0, outstanding_baseline_units_);
DCHECK_EQ(0, outstanding_top_tier_functions_); DCHECK_EQ(0, outstanding_top_tier_functions_);
compilation_progress_.reserve(module->num_declared_functions); compilation_progress_.reserve(module->num_declared_functions);
int start = module->num_imported_functions; int start = module->num_imported_functions;
int end = start + module->num_declared_functions; int end = start + module->num_declared_functions;
for (int func_index = start; func_index < end; func_index++) { for (int func_index = start; func_index < end; func_index++) {
...@@ -2047,7 +2110,7 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module) { ...@@ -2047,7 +2110,7 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module) {
strategy == CompileStrategy::kLazyBaselineEagerTopTier); strategy == CompileStrategy::kLazyBaselineEagerTopTier);
// Count functions to complete baseline and top tier compilation. // Count functions to complete baseline and top tier compilation.
if (required_for_baseline) outstanding_baseline_functions_++; if (required_for_baseline) outstanding_baseline_units_++;
if (required_for_top_tier) outstanding_top_tier_functions_++; if (required_for_top_tier) outstanding_top_tier_functions_++;
// Initialize function's compilation progress. // Initialize function's compilation progress.
...@@ -2063,18 +2126,18 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module) { ...@@ -2063,18 +2126,18 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module) {
RequiredTopTierField::update(function_progress, required_top_tier); RequiredTopTierField::update(function_progress, required_top_tier);
compilation_progress_.push_back(function_progress); compilation_progress_.push_back(function_progress);
} }
DCHECK_IMPLIES(lazy_module, outstanding_baseline_functions_ == 0); DCHECK_IMPLIES(lazy_module, outstanding_baseline_units_ == 0);
DCHECK_IMPLIES(lazy_module, outstanding_top_tier_functions_ == 0); DCHECK_IMPLIES(lazy_module, outstanding_top_tier_functions_ == 0);
DCHECK_LE(0, outstanding_baseline_functions_); DCHECK_LE(0, outstanding_baseline_units_);
DCHECK_LE(outstanding_baseline_functions_, outstanding_top_tier_functions_); DCHECK_LE(outstanding_baseline_units_, outstanding_top_tier_functions_);
outstanding_baseline_units_ += num_import_wrappers;
// Trigger callbacks if module needs no baseline or top tier compilation. This // Trigger callbacks if module needs no baseline or top tier compilation. This
// can be the case for an empty or fully lazy module. // can be the case for an empty or fully lazy module.
if (outstanding_baseline_functions_ == 0) { if (outstanding_baseline_units_ == 0) {
for (auto& callback : callbacks_) { for (auto& callback : callbacks_) {
callback(CompilationEvent::kFinishedBaselineCompilation); callback(CompilationEvent::kFinishedBaselineCompilation);
} }
}
if (outstanding_top_tier_functions_ == 0) { if (outstanding_top_tier_functions_ == 0) {
for (auto& callback : callbacks_) { for (auto& callback : callbacks_) {
callback(CompilationEvent::kFinishedTopTierCompilation); callback(CompilationEvent::kFinishedTopTierCompilation);
...@@ -2082,6 +2145,7 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module) { ...@@ -2082,6 +2145,7 @@ void CompilationStateImpl::InitializeCompilationProgress(bool lazy_module) {
// Clear the callbacks because no more events will be delivered. // Clear the callbacks because no more events will be delivered.
callbacks_.clear(); callbacks_.clear();
} }
}
} }
void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) { void CompilationStateImpl::AddCallback(CompilationState::callback_t callback) {
...@@ -2113,10 +2177,10 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { ...@@ -2113,10 +2177,10 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
base::MutexGuard guard(&callbacks_mutex_); base::MutexGuard guard(&callbacks_mutex_);
// In case of no outstanding functions we can return early. // In case of no outstanding compilation units we can return early.
// This is especially important for lazy modules that were deserialized. // This is especially important for lazy modules that were deserialized.
// Compilation progress was not set up in these cases. // Compilation progress was not set up in these cases.
if (outstanding_baseline_functions_ == 0 && if (outstanding_baseline_units_ == 0 &&
outstanding_top_tier_functions_ == 0) { outstanding_top_tier_functions_ == 0) {
return; return;
} }
...@@ -2133,6 +2197,20 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { ...@@ -2133,6 +2197,20 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
for (WasmCode* code : code_vector) { for (WasmCode* code : code_vector) {
DCHECK_NOT_NULL(code); DCHECK_NOT_NULL(code);
DCHECK_LT(code->index(), native_module_->num_functions());
bool completes_baseline_compilation = false;
bool completes_top_tier_compilation = false;
if (code->index() < native_module_->num_imported_functions()) {
// Import wrapper.
DCHECK_EQ(code->tier(), ExecutionTier::kTurbofan);
outstanding_baseline_units_--;
if (outstanding_baseline_units_ == 0) {
completes_baseline_compilation = true;
}
} else {
// Function.
DCHECK_NE(code->tier(), ExecutionTier::kNone); DCHECK_NE(code->tier(), ExecutionTier::kNone);
native_module_->engine()->LogCode(code); native_module_->engine()->LogCode(code);
...@@ -2149,19 +2227,17 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { ...@@ -2149,19 +2227,17 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
RequiredTopTierField::decode(function_progress); RequiredTopTierField::decode(function_progress);
ExecutionTier reached_tier = ReachedTierField::decode(function_progress); ExecutionTier reached_tier = ReachedTierField::decode(function_progress);
bool completes_baseline_compilation = false;
bool completes_top_tier_compilation = false;
// Check whether required baseline or top tier are reached. // Check whether required baseline or top tier are reached.
if (reached_tier < required_baseline_tier && if (reached_tier < required_baseline_tier &&
required_baseline_tier <= code->tier()) { required_baseline_tier <= code->tier()) {
DCHECK_GT(outstanding_baseline_functions_, 0); DCHECK_GT(outstanding_baseline_units_, 0);
outstanding_baseline_functions_--; outstanding_baseline_units_--;
if (outstanding_baseline_functions_ == 0) { if (outstanding_baseline_units_ == 0) {
completes_baseline_compilation = true; completes_baseline_compilation = true;
} }
} }
if (reached_tier < required_top_tier && required_top_tier <= code->tier()) { if (reached_tier < required_top_tier &&
required_top_tier <= code->tier()) {
DCHECK_GT(outstanding_top_tier_functions_, 0); DCHECK_GT(outstanding_top_tier_functions_, 0);
outstanding_top_tier_functions_--; outstanding_top_tier_functions_--;
if (outstanding_top_tier_functions_ == 0) { if (outstanding_top_tier_functions_ == 0) {
...@@ -2174,8 +2250,8 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { ...@@ -2174,8 +2250,8 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
compilation_progress_[slot_index] = ReachedTierField::update( compilation_progress_[slot_index] = ReachedTierField::update(
compilation_progress_[slot_index], code->tier()); compilation_progress_[slot_index], code->tier());
} }
DCHECK_LE(0, outstanding_baseline_functions_); DCHECK_LE(0, outstanding_baseline_units_);
DCHECK_LE(outstanding_baseline_functions_, outstanding_top_tier_functions_); }
// Trigger callbacks. // Trigger callbacks.
if (completes_baseline_compilation) { if (completes_baseline_compilation) {
...@@ -2183,8 +2259,11 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) { ...@@ -2183,8 +2259,11 @@ void CompilationStateImpl::OnFinishedUnits(Vector<WasmCode*> code_vector) {
for (auto& callback : callbacks_) { for (auto& callback : callbacks_) {
callback(CompilationEvent::kFinishedBaselineCompilation); callback(CompilationEvent::kFinishedBaselineCompilation);
} }
if (outstanding_top_tier_functions_ == 0) {
completes_top_tier_compilation = true;
} }
if (completes_top_tier_compilation) { }
if (outstanding_baseline_units_ == 0 && completes_top_tier_compilation) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "TopTierFinished"); TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "TopTierFinished");
for (auto& callback : callbacks_) { for (auto& callback : callbacks_) {
callback(CompilationEvent::kFinishedTopTierCompilation); callback(CompilationEvent::kFinishedTopTierCompilation);
...@@ -2311,14 +2390,21 @@ WasmCode* CompileImportWrapper( ...@@ -2311,14 +2390,21 @@ WasmCode* CompileImportWrapper(
bool source_positions = native_module->module()->origin == kAsmJsOrigin; bool source_positions = native_module->module()->origin == kAsmJsOrigin;
// Keep the {WasmCode} alive until we explicitly call {IncRef}. // Keep the {WasmCode} alive until we explicitly call {IncRef}.
WasmCodeRefScope code_ref_scope; WasmCodeRefScope code_ref_scope;
WasmCode* wasm_code = compiler::CompileWasmImportCallWrapper( CompilationEnv env = native_module->CreateCompilationEnv();
wasm_engine, native_module, kind, sig, source_positions); WasmCompilationResult result = compiler::CompileWasmImportCallWrapper(
(*cache_scope)[key] = wasm_code; wasm_engine, &env, kind, sig, source_positions);
wasm_code->IncRef(); std::unique_ptr<WasmCode> wasm_code = native_module->AddCode(
result.func_index, result.code_desc, result.frame_slot_count,
result.tagged_parameter_slots, std::move(result.protected_instructions),
std::move(result.source_positions), GetCodeKind(result),
ExecutionTier::kNone);
WasmCode* published_code = native_module->PublishCode(std::move(wasm_code));
(*cache_scope)[key] = published_code;
published_code->IncRef();
counters->wasm_generated_code_size()->Increment( counters->wasm_generated_code_size()->Increment(
wasm_code->instructions().length()); published_code->instructions().length());
counters->wasm_reloc_size()->Increment(wasm_code->reloc_info().length()); counters->wasm_reloc_size()->Increment(published_code->reloc_info().length());
return wasm_code; return published_code;
} }
Handle<Script> CreateWasmScript(Isolate* isolate, Handle<Script> CreateWasmScript(Isolate* isolate,
......
...@@ -822,7 +822,7 @@ WasmCode* NativeModule::AddAndPublishAnonymousCode(Handle<Code> code, ...@@ -822,7 +822,7 @@ WasmCode* NativeModule::AddAndPublishAnonymousCode(Handle<Code> code,
DCHECK_NE(kind, WasmCode::Kind::kInterpreterEntry); DCHECK_NE(kind, WasmCode::Kind::kInterpreterEntry);
std::unique_ptr<WasmCode> new_code{new WasmCode{ std::unique_ptr<WasmCode> new_code{new WasmCode{
this, // native_module this, // native_module
WasmCode::kAnonymousFuncIndex, // index kAnonymousFuncIndex, // index
dst_code_bytes, // instructions dst_code_bytes, // instructions
stack_slots, // stack_slots stack_slots, // stack_slots
0, // tagged_parameter_slots 0, // tagged_parameter_slots
...@@ -928,27 +928,26 @@ WasmCode* NativeModule::PublishCode(std::unique_ptr<WasmCode> code) { ...@@ -928,27 +928,26 @@ WasmCode* NativeModule::PublishCode(std::unique_ptr<WasmCode> code) {
return PublishCodeLocked(std::move(code)); return PublishCodeLocked(std::move(code));
} }
namespace { WasmCode::Kind GetCodeKind(const WasmCompilationResult& result) {
WasmCode::Kind GetCodeKindForExecutionTier(ExecutionTier tier) { switch (result.kind) {
switch (tier) { case WasmCompilationResult::kWasmToJsWrapper:
case ExecutionTier::kInterpreter: return WasmCode::Kind::kWasmToJsWrapper;
case WasmCompilationResult::kInterpreterEntry:
return WasmCode::Kind::kInterpreterEntry; return WasmCode::Kind::kInterpreterEntry;
case ExecutionTier::kLiftoff: case WasmCompilationResult::kFunction:
case ExecutionTier::kTurbofan:
return WasmCode::Kind::kFunction; return WasmCode::Kind::kFunction;
case ExecutionTier::kNone: default:
UNREACHABLE(); UNREACHABLE();
} }
} }
} // namespace
WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) { WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
// The caller must hold the {allocation_mutex_}, thus we fail to lock it here. // The caller must hold the {allocation_mutex_}, thus we fail to lock it here.
DCHECK(!allocation_mutex_.TryLock()); DCHECK(!allocation_mutex_.TryLock());
if (!code->IsAnonymous()) { if (!code->IsAnonymous() &&
code->index() >= module_->num_imported_functions) {
DCHECK_LT(code->index(), num_functions()); DCHECK_LT(code->index(), num_functions());
DCHECK_LE(module_->num_imported_functions, code->index());
// Assume an order of execution tiers that represents the quality of their // Assume an order of execution tiers that represents the quality of their
// generated code. // generated code.
...@@ -1054,7 +1053,7 @@ WasmCode* NativeModule::CreateEmptyJumpTable(uint32_t jump_table_size) { ...@@ -1054,7 +1053,7 @@ WasmCode* NativeModule::CreateEmptyJumpTable(uint32_t jump_table_size) {
ZapCode(reinterpret_cast<Address>(code_space.begin()), code_space.size()); ZapCode(reinterpret_cast<Address>(code_space.begin()), code_space.size());
std::unique_ptr<WasmCode> code{new WasmCode{ std::unique_ptr<WasmCode> code{new WasmCode{
this, // native_module this, // native_module
WasmCode::kAnonymousFuncIndex, // index kAnonymousFuncIndex, // index
code_space, // instructions code_space, // instructions
0, // stack_slots 0, // stack_slots
0, // tagged_parameter_slots 0, // tagged_parameter_slots
...@@ -1414,9 +1413,8 @@ std::vector<WasmCode*> NativeModule::AddCompiledCode( ...@@ -1414,9 +1413,8 @@ std::vector<WasmCode*> NativeModule::AddCompiledCode(
generated_code.emplace_back(AddCodeWithCodeSpace( generated_code.emplace_back(AddCodeWithCodeSpace(
result.func_index, result.code_desc, result.frame_slot_count, result.func_index, result.code_desc, result.frame_slot_count,
result.tagged_parameter_slots, std::move(result.protected_instructions), result.tagged_parameter_slots, std::move(result.protected_instructions),
std::move(result.source_positions), std::move(result.source_positions), GetCodeKind(result),
GetCodeKindForExecutionTier(result.result_tier), result.result_tier, result.result_tier, this_code_space));
this_code_space));
} }
DCHECK_EQ(0, code_space.size()); DCHECK_EQ(0, code_space.size());
......
...@@ -176,7 +176,6 @@ class V8_EXPORT_PRIVATE WasmCode final { ...@@ -176,7 +176,6 @@ class V8_EXPORT_PRIVATE WasmCode final {
enum FlushICache : bool { kFlushICache = true, kNoFlushICache = false }; enum FlushICache : bool { kFlushICache = true, kNoFlushICache = false };
static constexpr uint32_t kAnonymousFuncIndex = 0xffffffff;
STATIC_ASSERT(kAnonymousFuncIndex > kV8MaxWasmFunctions); STATIC_ASSERT(kAnonymousFuncIndex > kV8MaxWasmFunctions);
private: private:
...@@ -270,6 +269,8 @@ class V8_EXPORT_PRIVATE WasmCode final { ...@@ -270,6 +269,8 @@ class V8_EXPORT_PRIVATE WasmCode final {
DISALLOW_COPY_AND_ASSIGN(WasmCode); DISALLOW_COPY_AND_ASSIGN(WasmCode);
}; };
WasmCode::Kind GetCodeKind(const WasmCompilationResult& result);
// Return a textual description of the kind. // Return a textual description of the kind.
const char* GetWasmCodeKindAsString(WasmCode::Kind); const char* GetWasmCodeKindAsString(WasmCode::Kind);
......
...@@ -106,6 +106,8 @@ constexpr WasmCodePosition kNoCodePosition = -1; ...@@ -106,6 +106,8 @@ constexpr WasmCodePosition kNoCodePosition = -1;
constexpr uint32_t kExceptionAttribute = 0; constexpr uint32_t kExceptionAttribute = 0;
constexpr uint32_t kAnonymousFuncIndex = 0xffffffff;
} // namespace wasm } // namespace wasm
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -18,6 +18,11 @@ WasmCode*& WasmImportWrapperCache::ModificationScope::operator[]( ...@@ -18,6 +18,11 @@ WasmCode*& WasmImportWrapperCache::ModificationScope::operator[](
return cache_->entry_map_[key]; return cache_->entry_map_[key];
} }
WasmCode*& WasmImportWrapperCache::operator[](
const WasmImportWrapperCache::CacheKey& key) {
return entry_map_[key];
}
WasmCode* WasmImportWrapperCache::Get(compiler::WasmImportCallKind kind, WasmCode* WasmImportWrapperCache::Get(compiler::WasmImportCallKind kind,
FunctionSig* sig) const { FunctionSig* sig) const {
auto it = entry_map_.find({kind, sig}); auto it = entry_map_.find({kind, sig});
......
...@@ -45,6 +45,10 @@ class WasmImportWrapperCache { ...@@ -45,6 +45,10 @@ class WasmImportWrapperCache {
base::MutexGuard guard_; base::MutexGuard guard_;
}; };
// Not thread-safe, use ModificationScope to get exclusive write access to the
// cache.
V8_EXPORT_PRIVATE WasmCode*& operator[](const CacheKey& key);
// Assumes the key exists in the map. // Assumes the key exists in the map.
V8_EXPORT_PRIVATE WasmCode* Get(compiler::WasmImportCallKind kind, V8_EXPORT_PRIVATE WasmCode* Get(compiler::WasmImportCallKind kind,
FunctionSig* sig) const; FunctionSig* sig) const;
......
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