Commit 7a91e3c6 authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Add JSToWasmWrapperCache to reuse generated wrapper code

The generated code for JSToWasm wrappers only depends on the signature
of the exported function. Hence, we can reuse the generated code and
just patch the reference to the called wasm code.

For the unity-wasm benchmark, we reach a hit rate of 98.07% for this
cache, and only 395 instead of 20471 wrappers are compiled. This brings
down instantiation time from 2.9s to 1.6s on a MBP.

R=titzer@chromium.org

Review-Url: https://codereview.chromium.org/2705993002
Cr-Commit-Position: refs/heads/master@{#43322}
parent d8ccbd69
......@@ -32,7 +32,7 @@ class Signature : public ZoneObject {
return reps_[index];
}
bool Equals(Signature* that) {
bool Equals(const Signature* that) const {
if (this == that) return true;
if (this->parameter_count() != that->parameter_count()) return false;
if (this->return_count() != that->return_count()) return false;
......
......@@ -758,6 +758,47 @@ Handle<Script> CreateWasmScript(Isolate* isolate,
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,
......@@ -1022,13 +1063,13 @@ MaybeHandle<WasmModuleObject> CompileToModuleObject(
}
// 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_table->GetValueChecked<Code>(isolate, exp.index);
Handle<Code> wrapper_code =
compiler::CompileJSToWasmWrapper(isolate, m, wasm_code, exp.index);
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);
......@@ -1489,7 +1530,8 @@ class InstantiationHelper {
Handle<Code> startup_code =
code_table->GetValueChecked<Code>(isolate_, start_index);
FunctionSig* sig = module_->functions[start_index].sig;
Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
Handle<Code> wrapper_code =
js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper(
isolate_, module_, startup_code, start_index);
Handle<WasmExportedFunction> startup_fct = WasmExportedFunction::New(
isolate_, instance, MaybeHandle<String>(), start_index,
......@@ -1536,6 +1578,7 @@ class InstantiationHelper {
Handle<WasmCompiledModule> compiled_module_;
std::vector<TableInstance> table_instances_;
std::vector<Handle<JSFunction>> js_wrappers_;
JSToWasmWrapperCache js_to_wasm_cache_;
// Helper routines to print out errors with imports.
void ReportLinkError(const char* error, uint32_t index,
......@@ -2207,7 +2250,8 @@ class InstantiationHelper {
temp_instance.mem_start = nullptr;
temp_instance.globals_start = nullptr;
Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper(
Handle<Code> wrapper_code =
js_to_wasm_cache_.CloneOrCompileJSToWasmWrapper(
isolate_, module_, wasm_code, func_index);
MaybeHandle<String> func_name;
if (module_->origin == kAsmJsOrigin) {
......
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