e6414f6e24
Currently WebAssembly always goes through the ArgumentsAdaptorTrampoline builtin for wasm-to-js calls as soon as there's a mismatch between the actual number of arguments and the expected number of arguments. This can be made faster in cases where: 1. the callee has "don't adapt arguments" set, which is often the case for builtins, or 2. the callee has "skip adapt arguments" set, which is often the case for strict mode functions. TurboFan already supports this for JS calls: https://chromium-review.googlesource.com/c/1482735; explainer document: http://bit.ly/v8-faster-calls-with-arguments-mismatch. Even though it is probably not as common to have arity mismatches in Wasm->JS calls as it is in JS->JS calls, this still seems a worthwhile optimization to do. This CL ports the TurboFan fix to WebAssembly. In particular, the CL introduces a new WasmImportCallKind (kJSFunctionArityMismatchSkipAdaptor) for the case where the call to Builtins_ArgumentsAdaptorTrampoline can be skipped, and modifies WasmImportWrapperCache::CacheKey to also consider the arity of the imported JS function. A micro-benchmark for this change can be found here: - https://gist.github.com/paolosevMSFT/72c67591170d6163f67c9b03a7e12525#file-adapter-cc - https://gist.github.com/paolosevMSFT/72c67591170d6163f67c9b03a7e12525#file-adapter_test-js With this benchmark, we can save a 40% overhead of Builtins_ArgumentsAdaptorTrampoline for calls that pass too many arguments, while the savings for calls that pass too few arguments are less impressive: Before After callProperApplication: 563 ms 566 ms callOverApplication1: 972 ms 562 ms callOverApplication2: 962 ms 562 ms callUnderApplication: 949 ms 890 ms Bug: v8:8909 Change-Id: Id51764e7c422d00ecc4a48704323e11bdca9377f Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2317061 Commit-Queue: Paolo Severini <paolosev@microsoft.com> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Clemens Backes <clemensb@chromium.org> Cr-Commit-Position: refs/heads/master@{#69110}
152 lines
4.9 KiB
C++
152 lines
4.9 KiB
C++
// Copyright 2018 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/compiler/wasm-compiler.h"
|
|
#include "src/wasm/function-compiler.h"
|
|
#include "src/wasm/module-compiler.h"
|
|
#include "src/wasm/wasm-code-manager.h"
|
|
#include "src/wasm/wasm-engine.h"
|
|
#include "src/wasm/wasm-import-wrapper-cache.h"
|
|
#include "src/wasm/wasm-module.h"
|
|
|
|
#include "test/cctest/cctest.h"
|
|
#include "test/common/wasm/test-signatures.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace wasm {
|
|
namespace test_wasm_import_wrapper_cache {
|
|
|
|
std::shared_ptr<NativeModule> NewModule(Isolate* isolate) {
|
|
std::shared_ptr<WasmModule> module(new WasmModule);
|
|
constexpr size_t kCodeSizeEstimate = 16384;
|
|
auto native_module = isolate->wasm_engine()->NewNativeModule(
|
|
isolate, WasmFeatures::All(), std::move(module), kCodeSizeEstimate);
|
|
native_module->SetWireBytes({});
|
|
return native_module;
|
|
}
|
|
|
|
TEST(CacheHit) {
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
auto module = NewModule(isolate);
|
|
TestSignatures sigs;
|
|
WasmCodeRefScope wasm_code_ref_scope;
|
|
WasmImportWrapperCache::ModificationScope cache_scope(
|
|
module->import_wrapper_cache());
|
|
|
|
auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch;
|
|
auto sig = sigs.i_i();
|
|
int expected_arity = static_cast<int>(sig->parameter_count());
|
|
|
|
WasmCode* c1 = CompileImportWrapper(isolate->wasm_engine(), module.get(),
|
|
isolate->counters(), kind, sig,
|
|
expected_arity, &cache_scope);
|
|
|
|
CHECK_NOT_NULL(c1);
|
|
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
|
|
|
|
WasmCode* c2 = cache_scope[{kind, sig, expected_arity}];
|
|
|
|
CHECK_NOT_NULL(c2);
|
|
CHECK_EQ(c1, c2);
|
|
}
|
|
|
|
TEST(CacheMissSig) {
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
auto module = NewModule(isolate);
|
|
TestSignatures sigs;
|
|
WasmCodeRefScope wasm_code_ref_scope;
|
|
WasmImportWrapperCache::ModificationScope cache_scope(
|
|
module->import_wrapper_cache());
|
|
|
|
auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch;
|
|
auto sig1 = sigs.i_i();
|
|
int expected_arity1 = static_cast<int>(sig1->parameter_count());
|
|
auto sig2 = sigs.i_ii();
|
|
int expected_arity2 = static_cast<int>(sig2->parameter_count());
|
|
|
|
WasmCode* c1 = CompileImportWrapper(isolate->wasm_engine(), module.get(),
|
|
isolate->counters(), kind, sig1,
|
|
expected_arity1, &cache_scope);
|
|
|
|
CHECK_NOT_NULL(c1);
|
|
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
|
|
|
|
WasmCode* c2 = cache_scope[{kind, sig2, expected_arity2}];
|
|
|
|
CHECK_NULL(c2);
|
|
}
|
|
|
|
TEST(CacheMissKind) {
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
auto module = NewModule(isolate);
|
|
TestSignatures sigs;
|
|
WasmCodeRefScope wasm_code_ref_scope;
|
|
WasmImportWrapperCache::ModificationScope cache_scope(
|
|
module->import_wrapper_cache());
|
|
|
|
auto kind1 = compiler::WasmImportCallKind::kJSFunctionArityMatch;
|
|
auto kind2 = compiler::WasmImportCallKind::kJSFunctionArityMismatch;
|
|
auto sig = sigs.i_i();
|
|
int expected_arity = static_cast<int>(sig->parameter_count());
|
|
|
|
WasmCode* c1 = CompileImportWrapper(isolate->wasm_engine(), module.get(),
|
|
isolate->counters(), kind1, sig,
|
|
expected_arity, &cache_scope);
|
|
|
|
CHECK_NOT_NULL(c1);
|
|
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
|
|
|
|
WasmCode* c2 = cache_scope[{kind2, sig, expected_arity}];
|
|
|
|
CHECK_NULL(c2);
|
|
}
|
|
|
|
TEST(CacheHitMissSig) {
|
|
Isolate* isolate = CcTest::InitIsolateOnce();
|
|
auto module = NewModule(isolate);
|
|
TestSignatures sigs;
|
|
WasmCodeRefScope wasm_code_ref_scope;
|
|
WasmImportWrapperCache::ModificationScope cache_scope(
|
|
module->import_wrapper_cache());
|
|
|
|
auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch;
|
|
auto sig1 = sigs.i_i();
|
|
int expected_arity1 = static_cast<int>(sig1->parameter_count());
|
|
auto sig2 = sigs.i_ii();
|
|
int expected_arity2 = static_cast<int>(sig2->parameter_count());
|
|
|
|
WasmCode* c1 = CompileImportWrapper(isolate->wasm_engine(), module.get(),
|
|
isolate->counters(), kind, sig1,
|
|
expected_arity1, &cache_scope);
|
|
|
|
CHECK_NOT_NULL(c1);
|
|
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
|
|
|
|
WasmCode* c2 = cache_scope[{kind, sig2, expected_arity2}];
|
|
|
|
CHECK_NULL(c2);
|
|
|
|
c2 = CompileImportWrapper(isolate->wasm_engine(), module.get(),
|
|
isolate->counters(), kind, sig2, expected_arity2,
|
|
&cache_scope);
|
|
|
|
CHECK_NE(c1, c2);
|
|
|
|
WasmCode* c3 = cache_scope[{kind, sig1, expected_arity1}];
|
|
|
|
CHECK_NOT_NULL(c3);
|
|
CHECK_EQ(c1, c3);
|
|
|
|
WasmCode* c4 = cache_scope[{kind, sig2, expected_arity2}];
|
|
|
|
CHECK_NOT_NULL(c4);
|
|
CHECK_EQ(c2, c4);
|
|
}
|
|
|
|
} // namespace test_wasm_import_wrapper_cache
|
|
} // namespace wasm
|
|
} // namespace internal
|
|
} // namespace v8
|