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,10 +6103,9 @@ wasm::WasmOpcode GetMathIntrinsicOpcode(WasmImportCallKind kind,
#undef CASE
}
wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine,
wasm::NativeModule* native_module,
WasmImportCallKind kind,
wasm::FunctionSig* sig) {
wasm::WasmCompilationResult CompileWasmMathIntrinsic(
wasm::WasmEngine* wasm_engine, WasmImportCallKind kind,
wasm::FunctionSig* sig) {
DCHECK_EQ(1, sig->return_count());
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"),
......@@ -6125,7 +6124,7 @@ wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine,
InstructionSelector::AlignmentRequirements()));
wasm::CompilationEnv env(
native_module->module(), wasm::UseTrapHandler::kNoTrapHandler,
nullptr, wasm::UseTrapHandler::kNoTrapHandler,
wasm::RuntimeExceptionSupport::kNoRuntimeExceptionSupport,
wasm::kAllWasmFeatures, wasm::LowerSimd::kNoLowerSimd);
......@@ -6167,21 +6166,12 @@ wasm::WasmCode* CompileWasmMathIntrinsic(wasm::WasmEngine* wasm_engine,
wasm_engine, call_descriptor, mcgraph, Code::WASM_FUNCTION,
wasm::WasmCode::kFunction, debug_name, WasmStubAssemblerOptions(),
source_positions);
std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
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));
return result;
}
wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
wasm::NativeModule* native_module,
WasmImportCallKind kind,
wasm::FunctionSig* sig,
bool source_positions) {
wasm::WasmCompilationResult CompileWasmImportCallWrapper(
wasm::WasmEngine* wasm_engine, wasm::CompilationEnv* env,
WasmImportCallKind kind, wasm::FunctionSig* sig, bool source_positions) {
DCHECK_NE(WasmImportCallKind::kLinkError, kind);
DCHECK_NE(WasmImportCallKind::kWasmToWasm, kind);
......@@ -6189,7 +6179,7 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
if (FLAG_wasm_math_intrinsics &&
kind >= WasmImportCallKind::kFirstMathIntrinsic &&
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"),
......@@ -6214,7 +6204,7 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
WasmWrapperGraphBuilder builder(&zone, &jsgraph, sig, source_position_table,
StubCallMode::kCallWasmRuntimeStub,
native_module->enabled_features());
env->enabled_features);
builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect);
builder.BuildWasmImportCallWrapper(kind);
......@@ -6232,13 +6222,8 @@ wasm::WasmCode* CompileWasmImportCallWrapper(wasm::WasmEngine* wasm_engine,
wasm_engine, incoming, &jsgraph, Code::WASM_TO_JS_FUNCTION,
wasm::WasmCode::kWasmToJsWrapper, func_name, WasmStubAssemblerOptions(),
source_position_table);
std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
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::kWasmToJsWrapper,
wasm::ExecutionTier::kNone);
return native_module->PublishCode(std::move(wasm_code));
result.kind = wasm::WasmCompilationResult::kWasmToJsWrapper;
return result;
}
wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine,
......@@ -6290,9 +6275,8 @@ wasm::WasmCode* CompileWasmCapiCallWrapper(wasm::WasmEngine* wasm_engine,
wasm::WasmCode::kWasmToCapiWrapper, debug_name,
WasmStubAssemblerOptions(), source_positions);
std::unique_ptr<wasm::WasmCode> wasm_code = native_module->AddCode(
wasm::WasmCode::kAnonymousFuncIndex, result.code_desc,
result.frame_slot_count, result.tagged_parameter_slots,
std::move(result.protected_instructions),
wasm::kAnonymousFuncIndex, result.code_desc, result.frame_slot_count,
result.tagged_parameter_slots, std::move(result.protected_instructions),
std::move(result.source_positions), wasm::WasmCode::kWasmToCapiWrapper,
wasm::ExecutionTier::kNone);
return native_module->PublishCode(std::move(wasm_code));
......@@ -6338,6 +6322,7 @@ wasm::WasmCompilationResult CompileWasmInterpreterEntry(
wasm::WasmCode::kInterpreterEntry, func_name.begin(),
WasmStubAssemblerOptions());
result.result_tier = wasm::ExecutionTier::kInterpreter;
result.kind = wasm::WasmCompilationResult::kInterpreterEntry;
return result;
}
......
......@@ -103,13 +103,19 @@ enum class WasmImportCallKind : uint8_t {
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
GetWasmImportCallKind(Handle<JSReceiver> callable, wasm::FunctionSig* sig,
bool has_bigint_feature);
// Compiles an import call wrapper, which allows WASM to call imports.
V8_EXPORT_PRIVATE wasm::WasmCode* CompileWasmImportCallWrapper(
wasm::WasmEngine*, wasm::NativeModule*, WasmImportCallKind,
V8_EXPORT_PRIVATE wasm::WasmCompilationResult CompileWasmImportCallWrapper(
wasm::WasmEngine*, wasm::CompilationEnv* env, WasmImportCallKind,
wasm::FunctionSig*, bool source_positions);
// Compiles a host call wrapper, which allows WASM to call host functions.
......
......@@ -113,6 +113,42 @@ ExecutionTier WasmCompilationUnit::GetDefaultExecutionTier(
}
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,
const std::shared_ptr<WireBytesStorage>& wire_bytes_storage,
Counters* counters, WasmFeatures* detected) {
......@@ -167,15 +203,6 @@ WasmCompilationResult WasmCompilationUnit::ExecuteCompilation(
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;
}
......@@ -190,6 +217,8 @@ void WasmCompilationUnit::CompileWasmFunction(Isolate* isolate,
wire_bytes.start() + function->code.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);
CompilationEnv env = native_module->CreateCompilationEnv();
WasmCompilationResult result = unit.ExecuteCompilation(
......
......@@ -43,6 +43,12 @@ struct WasmCompilationResult {
public:
MOVE_ONLY_WITH_DEFAULT_CONSTRUCTORS(WasmCompilationResult);
enum Kind : int8_t {
kFunction,
kWasmToJsWrapper,
kInterpreterEntry,
};
bool succeeded() const { return code_desc.buffer != nullptr; }
bool failed() const { return !succeeded(); }
operator bool() const { return succeeded(); }
......@@ -53,9 +59,10 @@ struct WasmCompilationResult {
uint32_t tagged_parameter_slots = 0;
OwnedVector<byte> source_positions;
OwnedVector<trap_handler::ProtectedInstructionData> protected_instructions;
int func_index;
int func_index = static_cast<int>(kAnonymousFuncIndex);
ExecutionTier requested_tier;
ExecutionTier result_tier;
Kind kind = kFunction;
};
class V8_EXPORT_PRIVATE WasmCompilationUnit final {
......@@ -77,6 +84,14 @@ class V8_EXPORT_PRIVATE WasmCompilationUnit final {
ExecutionTier);
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_;
ExecutionTier tier_;
};
......
This diff is collapsed.
......@@ -822,7 +822,7 @@ WasmCode* NativeModule::AddAndPublishAnonymousCode(Handle<Code> code,
DCHECK_NE(kind, WasmCode::Kind::kInterpreterEntry);
std::unique_ptr<WasmCode> new_code{new WasmCode{
this, // native_module
WasmCode::kAnonymousFuncIndex, // index
kAnonymousFuncIndex, // index
dst_code_bytes, // instructions
stack_slots, // stack_slots
0, // tagged_parameter_slots
......@@ -928,27 +928,26 @@ WasmCode* NativeModule::PublishCode(std::unique_ptr<WasmCode> code) {
return PublishCodeLocked(std::move(code));
}
namespace {
WasmCode::Kind GetCodeKindForExecutionTier(ExecutionTier tier) {
switch (tier) {
case ExecutionTier::kInterpreter:
WasmCode::Kind GetCodeKind(const WasmCompilationResult& result) {
switch (result.kind) {
case WasmCompilationResult::kWasmToJsWrapper:
return WasmCode::Kind::kWasmToJsWrapper;
case WasmCompilationResult::kInterpreterEntry:
return WasmCode::Kind::kInterpreterEntry;
case ExecutionTier::kLiftoff:
case ExecutionTier::kTurbofan:
case WasmCompilationResult::kFunction:
return WasmCode::Kind::kFunction;
case ExecutionTier::kNone:
default:
UNREACHABLE();
}
}
} // namespace
WasmCode* NativeModule::PublishCodeLocked(std::unique_ptr<WasmCode> code) {
// The caller must hold the {allocation_mutex_}, thus we fail to lock it here.
DCHECK(!allocation_mutex_.TryLock());
if (!code->IsAnonymous()) {
if (!code->IsAnonymous() &&
code->index() >= module_->num_imported_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
// generated code.
......@@ -1054,7 +1053,7 @@ WasmCode* NativeModule::CreateEmptyJumpTable(uint32_t jump_table_size) {
ZapCode(reinterpret_cast<Address>(code_space.begin()), code_space.size());
std::unique_ptr<WasmCode> code{new WasmCode{
this, // native_module
WasmCode::kAnonymousFuncIndex, // index
kAnonymousFuncIndex, // index
code_space, // instructions
0, // stack_slots
0, // tagged_parameter_slots
......@@ -1414,9 +1413,8 @@ std::vector<WasmCode*> NativeModule::AddCompiledCode(
generated_code.emplace_back(AddCodeWithCodeSpace(
result.func_index, result.code_desc, result.frame_slot_count,
result.tagged_parameter_slots, std::move(result.protected_instructions),
std::move(result.source_positions),
GetCodeKindForExecutionTier(result.result_tier), result.result_tier,
this_code_space));
std::move(result.source_positions), GetCodeKind(result),
result.result_tier, this_code_space));
}
DCHECK_EQ(0, code_space.size());
......
......@@ -176,7 +176,6 @@ class V8_EXPORT_PRIVATE WasmCode final {
enum FlushICache : bool { kFlushICache = true, kNoFlushICache = false };
static constexpr uint32_t kAnonymousFuncIndex = 0xffffffff;
STATIC_ASSERT(kAnonymousFuncIndex > kV8MaxWasmFunctions);
private:
......@@ -270,6 +269,8 @@ class V8_EXPORT_PRIVATE WasmCode final {
DISALLOW_COPY_AND_ASSIGN(WasmCode);
};
WasmCode::Kind GetCodeKind(const WasmCompilationResult& result);
// Return a textual description of the kind.
const char* GetWasmCodeKindAsString(WasmCode::Kind);
......
......@@ -106,6 +106,8 @@ constexpr WasmCodePosition kNoCodePosition = -1;
constexpr uint32_t kExceptionAttribute = 0;
constexpr uint32_t kAnonymousFuncIndex = 0xffffffff;
} // namespace wasm
} // namespace internal
} // namespace v8
......
......@@ -18,6 +18,11 @@ WasmCode*& WasmImportWrapperCache::ModificationScope::operator[](
return cache_->entry_map_[key];
}
WasmCode*& WasmImportWrapperCache::operator[](
const WasmImportWrapperCache::CacheKey& key) {
return entry_map_[key];
}
WasmCode* WasmImportWrapperCache::Get(compiler::WasmImportCallKind kind,
FunctionSig* sig) const {
auto it = entry_map_.find({kind, sig});
......
......@@ -45,6 +45,10 @@ class WasmImportWrapperCache {
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.
V8_EXPORT_PRIVATE WasmCode* Get(compiler::WasmImportCallKind kind,
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