Commit f2b98fa8 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm] Index wrappers by isorecursive canonical type

Before, import and export wrappers were cached based on their
signature. This change
- makes wrapper canonicalization consistent with that of types and
  call_indirect signatures under --wasm-type-canonicalization,
- removes the last uses of signature maps, which will enable us to
  remove them in a future CL.

Change-Id: I512bc234f0ae10e50bd94237e8e675ca47ed13c5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3891250
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83183}
parent 74c2cec6
...@@ -293,6 +293,8 @@ RUNTIME_FUNCTION(Runtime_WasmCompileWrapper) { ...@@ -293,6 +293,8 @@ RUNTIME_FUNCTION(Runtime_WasmCompileWrapper) {
const int function_index = function_data->function_index(); const int function_index = function_data->function_index();
const wasm::WasmFunction& function = module->functions[function_index]; const wasm::WasmFunction& function = module->functions[function_index];
const wasm::FunctionSig* sig = function.sig; const wasm::FunctionSig* sig = function.sig;
const uint32_t canonical_sig_index =
module->isorecursive_canonical_type_ids[function.sig_index];
// The start function is not guaranteed to be registered as // The start function is not guaranteed to be registered as
// an exported function (although it is called as one). // an exported function (although it is called as one).
...@@ -307,7 +309,7 @@ RUNTIME_FUNCTION(Runtime_WasmCompileWrapper) { ...@@ -307,7 +309,7 @@ RUNTIME_FUNCTION(Runtime_WasmCompileWrapper) {
Handle<CodeT> wrapper_code = Handle<CodeT> wrapper_code =
wasm::JSToWasmWrapperCompilationUnit::CompileSpecificJSToWasmWrapper( wasm::JSToWasmWrapperCompilationUnit::CompileSpecificJSToWasmWrapper(
isolate, sig, module); isolate, sig, canonical_sig_index, module);
// Replace the wrapper for the function that triggered the tier-up. // Replace the wrapper for the function that triggered the tier-up.
// This is to verify that the wrapper is replaced, even if the function // This is to verify that the wrapper is replaced, even if the function
......
...@@ -10,7 +10,7 @@ namespace v8 { ...@@ -10,7 +10,7 @@ namespace v8 {
namespace internal { namespace internal {
namespace wasm { namespace wasm {
V8_EXPORT_PRIVATE TypeCanonicalizer* GetTypeCanonicalizer() { TypeCanonicalizer* GetTypeCanonicalizer() {
return GetWasmEngine()->type_canonicalizer(); return GetWasmEngine()->type_canonicalizer();
} }
...@@ -55,6 +55,33 @@ void TypeCanonicalizer::AddRecursiveGroup(WasmModule* module, uint32_t size) { ...@@ -55,6 +55,33 @@ void TypeCanonicalizer::AddRecursiveGroup(WasmModule* module, uint32_t size) {
} }
} }
uint32_t TypeCanonicalizer::AddRecursiveGroup(const FunctionSig* sig) {
base::MutexGuard mutex_guard(&mutex_);
// Types in the signature must be module-independent.
#if DEBUG
for (ValueType type : sig->all()) DCHECK(!type.has_index());
#endif
CanonicalGroup group;
group.types.resize(1);
group.types[0].type_def = TypeDefinition(sig, kNoSuperType);
group.types[0].is_relative_supertype = false;
int canonical_index = FindCanonicalGroup(group);
if (canonical_index < 0) {
canonical_index = static_cast<int>(canonical_supertypes_.size());
// We need to copy the signature in the local zone, or else we risk
// storing a dangling pointer in the future.
auto builder = FunctionSig::Builder(&zone_, sig->return_count(),
sig->parameter_count());
for (auto type : sig->returns()) builder.AddReturn(type);
for (auto type : sig->parameters()) builder.AddParam(type);
const FunctionSig* allocated_sig = builder.Build();
group.types[0].type_def = TypeDefinition(allocated_sig, kNoSuperType);
canonical_groups_.emplace(group, canonical_index);
canonical_supertypes_.emplace_back(kNoSuperType);
}
return canonical_index;
}
// An index in a type gets mapped to a relative index if it is inside the new // An index in a type gets mapped to a relative index if it is inside the new
// canonical group, or the canonical representative if it is not. // canonical group, or the canonical representative if it is not.
ValueType TypeCanonicalizer::CanonicalizeValueType( ValueType TypeCanonicalizer::CanonicalizeValueType(
...@@ -88,8 +115,8 @@ bool TypeCanonicalizer::IsCanonicalSubtype(uint32_t sub_index, ...@@ -88,8 +115,8 @@ bool TypeCanonicalizer::IsCanonicalSubtype(uint32_t sub_index,
return false; return false;
} }
// Map all type indices (including supertype) inside {type} to indices relative // Map all type indices (including supertype) inside {type} to indices
// to {recursive_group_start}. // relative to {recursive_group_start}.
TypeCanonicalizer::CanonicalType TypeCanonicalizer::CanonicalizeTypeDef( TypeCanonicalizer::CanonicalType TypeCanonicalizer::CanonicalizeTypeDef(
const WasmModule* module, TypeDefinition type, const WasmModule* module, TypeDefinition type,
uint32_t recursive_group_start) { uint32_t recursive_group_start) {
......
...@@ -43,6 +43,11 @@ class TypeCanonicalizer { ...@@ -43,6 +43,11 @@ class TypeCanonicalizer {
// Modifies {module->isorecursive_canonical_type_ids}. // Modifies {module->isorecursive_canonical_type_ids}.
V8_EXPORT_PRIVATE void AddRecursiveGroup(WasmModule* module, uint32_t size); V8_EXPORT_PRIVATE void AddRecursiveGroup(WasmModule* module, uint32_t size);
// Adds a module-independent signature as a recursive group, and canonicalizes
// it if an identical is found. Returns the canonical index of the added
// signature.
V8_EXPORT_PRIVATE uint32_t AddRecursiveGroup(const FunctionSig* sig);
// Returns if the type at {sub_index} in {sub_module} is a subtype of the // Returns if the type at {sub_index} in {sub_module} is a subtype of the
// type at {super_index} in {super_module} after canonicalization. // type at {super_index} in {super_module} after canonicalization.
V8_EXPORT_PRIVATE bool IsCanonicalSubtype(uint32_t sub_index, V8_EXPORT_PRIVATE bool IsCanonicalSubtype(uint32_t sub_index,
......
...@@ -204,12 +204,13 @@ bool UseGenericWrapper(const FunctionSig* sig) { ...@@ -204,12 +204,13 @@ bool UseGenericWrapper(const FunctionSig* sig) {
} // namespace } // namespace
JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit( JSToWasmWrapperCompilationUnit::JSToWasmWrapperCompilationUnit(
Isolate* isolate, const FunctionSig* sig, const WasmModule* module, Isolate* isolate, const FunctionSig* sig, uint32_t canonical_sig_index,
bool is_import, const WasmFeatures& enabled_features, const WasmModule* module, bool is_import,
AllowGeneric allow_generic) const WasmFeatures& enabled_features, AllowGeneric allow_generic)
: isolate_(isolate), : isolate_(isolate),
is_import_(is_import), is_import_(is_import),
sig_(sig), sig_(sig),
canonical_sig_index_(canonical_sig_index),
use_generic_wrapper_(allow_generic && UseGenericWrapper(sig) && use_generic_wrapper_(allow_generic && UseGenericWrapper(sig) &&
!is_import), !is_import),
job_(use_generic_wrapper_ job_(use_generic_wrapper_
...@@ -248,24 +249,27 @@ Handle<CodeT> JSToWasmWrapperCompilationUnit::Finalize() { ...@@ -248,24 +249,27 @@ Handle<CodeT> JSToWasmWrapperCompilationUnit::Finalize() {
// static // static
Handle<CodeT> JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper( Handle<CodeT> JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
Isolate* isolate, const FunctionSig* sig, const WasmModule* module, Isolate* isolate, const FunctionSig* sig, uint32_t canonical_sig_index,
bool is_import) { const WasmModule* module, bool is_import) {
// Run the compilation unit synchronously. // Run the compilation unit synchronously.
WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate); WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate);
JSToWasmWrapperCompilationUnit unit(isolate, sig, module, is_import, JSToWasmWrapperCompilationUnit unit(isolate, sig, canonical_sig_index, module,
enabled_features, kAllowGeneric); is_import, enabled_features,
kAllowGeneric);
unit.Execute(); unit.Execute();
return unit.Finalize(); return unit.Finalize();
} }
// static // static
Handle<CodeT> JSToWasmWrapperCompilationUnit::CompileSpecificJSToWasmWrapper( Handle<CodeT> JSToWasmWrapperCompilationUnit::CompileSpecificJSToWasmWrapper(
Isolate* isolate, const FunctionSig* sig, const WasmModule* module) { Isolate* isolate, const FunctionSig* sig, uint32_t canonical_sig_index,
const WasmModule* module) {
// Run the compilation unit synchronously. // Run the compilation unit synchronously.
const bool is_import = false; const bool is_import = false;
WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate); WasmFeatures enabled_features = WasmFeatures::FromIsolate(isolate);
JSToWasmWrapperCompilationUnit unit(isolate, sig, module, is_import, JSToWasmWrapperCompilationUnit unit(isolate, sig, canonical_sig_index, module,
enabled_features, kDontAllowGeneric); is_import, enabled_features,
kDontAllowGeneric);
unit.Execute(); unit.Execute();
return unit.Finalize(); return unit.Finalize();
} }
......
...@@ -104,6 +104,7 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final { ...@@ -104,6 +104,7 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final {
enum AllowGeneric : bool { kAllowGeneric = true, kDontAllowGeneric = false }; enum AllowGeneric : bool { kAllowGeneric = true, kDontAllowGeneric = false };
JSToWasmWrapperCompilationUnit(Isolate* isolate, const FunctionSig* sig, JSToWasmWrapperCompilationUnit(Isolate* isolate, const FunctionSig* sig,
uint32_t canonical_sig_index,
const wasm::WasmModule* module, bool is_import, const wasm::WasmModule* module, bool is_import,
const WasmFeatures& enabled_features, const WasmFeatures& enabled_features,
AllowGeneric allow_generic); AllowGeneric allow_generic);
...@@ -116,17 +117,19 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final { ...@@ -116,17 +117,19 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final {
bool is_import() const { return is_import_; } bool is_import() const { return is_import_; }
const FunctionSig* sig() const { return sig_; } const FunctionSig* sig() const { return sig_; }
uint32_t canonical_sig_index() const { return canonical_sig_index_; }
// Run a compilation unit synchronously. // Run a compilation unit synchronously.
static Handle<CodeT> CompileJSToWasmWrapper(Isolate* isolate, static Handle<CodeT> CompileJSToWasmWrapper(Isolate* isolate,
const FunctionSig* sig, const FunctionSig* sig,
uint32_t canonical_sig_index,
const WasmModule* module, const WasmModule* module,
bool is_import); bool is_import);
// Run a compilation unit synchronously, but ask for the specific // Run a compilation unit synchronously, but ask for the specific
// wrapper. // wrapper.
static Handle<CodeT> CompileSpecificJSToWasmWrapper(Isolate* isolate, static Handle<CodeT> CompileSpecificJSToWasmWrapper(
const FunctionSig* sig, Isolate* isolate, const FunctionSig* sig, uint32_t canonical_sig_index,
const WasmModule* module); const WasmModule* module);
private: private:
...@@ -137,6 +140,7 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final { ...@@ -137,6 +140,7 @@ class V8_EXPORT_PRIVATE JSToWasmWrapperCompilationUnit final {
Isolate* isolate_; Isolate* isolate_;
bool is_import_; bool is_import_;
const FunctionSig* sig_; const FunctionSig* sig_;
uint32_t canonical_sig_index_;
bool use_generic_wrapper_; bool use_generic_wrapper_;
std::unique_ptr<TurbofanCompilationJob> job_; std::unique_ptr<TurbofanCompilationJob> job_;
}; };
......
...@@ -1713,7 +1713,8 @@ CompilationExecutionResult ExecuteCompilationUnits( ...@@ -1713,7 +1713,8 @@ CompilationExecutionResult ExecuteCompilationUnits(
UNREACHABLE(); UNREACHABLE();
} }
using JSToWasmWrapperKey = std::pair<bool, FunctionSig>; // (function is imported, canonical type index)
using JSToWasmWrapperKey = std::pair<bool, uint32_t>;
// Returns the number of units added. // Returns the number of units added.
int AddExportWrapperUnits(Isolate* isolate, NativeModule* native_module, int AddExportWrapperUnits(Isolate* isolate, NativeModule* native_module,
...@@ -1722,11 +1723,14 @@ int AddExportWrapperUnits(Isolate* isolate, NativeModule* native_module, ...@@ -1722,11 +1723,14 @@ int AddExportWrapperUnits(Isolate* isolate, NativeModule* native_module,
for (auto exp : native_module->module()->export_table) { for (auto exp : native_module->module()->export_table) {
if (exp.kind != kExternalFunction) continue; if (exp.kind != kExternalFunction) continue;
auto& function = native_module->module()->functions[exp.index]; auto& function = native_module->module()->functions[exp.index];
JSToWasmWrapperKey key(function.imported, *function.sig); uint32_t canonical_type_index =
native_module->module()
->isorecursive_canonical_type_ids[function.sig_index];
JSToWasmWrapperKey key(function.imported, canonical_type_index);
if (keys.insert(key).second) { if (keys.insert(key).second) {
auto unit = std::make_shared<JSToWasmWrapperCompilationUnit>( auto unit = std::make_shared<JSToWasmWrapperCompilationUnit>(
isolate, function.sig, native_module->module(), function.imported, isolate, function.sig, canonical_type_index, native_module->module(),
native_module->enabled_features(), function.imported, native_module->enabled_features(),
JSToWasmWrapperCompilationUnit::kAllowGeneric); JSToWasmWrapperCompilationUnit::kAllowGeneric);
builder->AddJSToWasmWrapperUnit(std::move(unit)); builder->AddJSToWasmWrapperUnit(std::move(unit));
} }
...@@ -1743,14 +1747,18 @@ int AddImportWrapperUnits(NativeModule* native_module, ...@@ -1743,14 +1747,18 @@ int AddImportWrapperUnits(NativeModule* native_module,
keys; keys;
int num_imported_functions = native_module->num_imported_functions(); int num_imported_functions = native_module->num_imported_functions();
for (int func_index = 0; func_index < num_imported_functions; func_index++) { for (int func_index = 0; func_index < num_imported_functions; func_index++) {
const FunctionSig* sig = native_module->module()->functions[func_index].sig; const WasmFunction& function =
if (!IsJSCompatibleSignature(sig, native_module->module(), native_module->module()->functions[func_index];
if (!IsJSCompatibleSignature(function.sig, native_module->module(),
native_module->enabled_features())) { native_module->enabled_features())) {
continue; continue;
} }
uint32_t canonical_type_index =
native_module->module()
->isorecursive_canonical_type_ids[function.sig_index];
WasmImportWrapperCache::CacheKey key( WasmImportWrapperCache::CacheKey key(
compiler::kDefaultImportCallKind, sig, compiler::kDefaultImportCallKind, canonical_type_index,
static_cast<int>(sig->parameter_count()), kNoSuspend); static_cast<int>(function.sig->parameter_count()), kNoSuspend);
auto it = keys.insert(key); auto it = keys.insert(key);
if (it.second) { if (it.second) {
// Ensure that all keys exist in the cache, so that we can populate the // Ensure that all keys exist in the cache, so that we can populate the
...@@ -3553,8 +3561,8 @@ void CompilationStateImpl::FinalizeJSToWasmWrappers( ...@@ -3553,8 +3561,8 @@ void CompilationStateImpl::FinalizeJSToWasmWrappers(
for (auto& unit : js_to_wasm_wrapper_units_) { for (auto& unit : js_to_wasm_wrapper_units_) {
DCHECK_EQ(isolate, unit->isolate()); DCHECK_EQ(isolate, unit->isolate());
Handle<CodeT> code = unit->Finalize(); Handle<CodeT> code = unit->Finalize();
int wrapper_index = int wrapper_index = GetExportWrapperIndex(
GetExportWrapperIndex(module, unit->sig(), unit->is_import()); module, unit->canonical_sig_index(), unit->is_import());
(*export_wrappers_out)->set(wrapper_index, *code); (*export_wrappers_out)->set(wrapper_index, *code);
RecordStats(*code, isolate->counters()); RecordStats(*code, isolate->counters());
} }
...@@ -3752,11 +3760,14 @@ void CompilationStateImpl::PublishCompilationResults( ...@@ -3752,11 +3760,14 @@ void CompilationStateImpl::PublishCompilationResults(
DCHECK_LE(0, func_index); DCHECK_LE(0, func_index);
DCHECK_LT(func_index, native_module_->num_functions()); DCHECK_LT(func_index, native_module_->num_functions());
if (func_index < num_imported_functions) { if (func_index < num_imported_functions) {
const FunctionSig* sig = const WasmFunction& function =
native_module_->module()->functions[func_index].sig; native_module_->module()->functions[func_index];
uint32_t canonical_type_index =
native_module_->module()
->isorecursive_canonical_type_ids[function.sig_index];
WasmImportWrapperCache::CacheKey key( WasmImportWrapperCache::CacheKey key(
compiler::kDefaultImportCallKind, sig, compiler::kDefaultImportCallKind, canonical_type_index,
static_cast<int>(sig->parameter_count()), kNoSuspend); static_cast<int>(function.sig->parameter_count()), kNoSuspend);
// If two imported functions have the same key, only one of them should // 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 // have been added as a compilation unit. So it is always the first time
// we compile a wrapper for this key here. // we compile a wrapper for this key here.
...@@ -3889,8 +3900,8 @@ void CompilationStateImpl::WaitForCompilationEvent( ...@@ -3889,8 +3900,8 @@ void CompilationStateImpl::WaitForCompilationEvent(
} }
namespace { namespace {
using JSToWasmWrapperQueue = using JSToWasmWrapperQueue = WrapperQueue<JSToWasmWrapperKey, std::nullptr_t,
WrapperQueue<JSToWasmWrapperKey, base::hash<JSToWasmWrapperKey>>; base::hash<JSToWasmWrapperKey>>;
using JSToWasmWrapperUnitMap = using JSToWasmWrapperUnitMap =
std::unordered_map<JSToWasmWrapperKey, std::unordered_map<JSToWasmWrapperKey,
std::unique_ptr<JSToWasmWrapperCompilationUnit>, std::unique_ptr<JSToWasmWrapperCompilationUnit>,
...@@ -3905,8 +3916,10 @@ class CompileJSToWasmWrapperJob final : public JobTask { ...@@ -3905,8 +3916,10 @@ class CompileJSToWasmWrapperJob final : public JobTask {
outstanding_units_(queue->size()) {} outstanding_units_(queue->size()) {}
void Run(JobDelegate* delegate) override { void Run(JobDelegate* delegate) override {
while (base::Optional<JSToWasmWrapperKey> key = queue_->pop()) { while (base::Optional<std::pair<JSToWasmWrapperKey, std::nullptr_t>> key =
JSToWasmWrapperCompilationUnit* unit = (*compilation_units_)[*key].get(); queue_->pop()) {
JSToWasmWrapperCompilationUnit* unit =
(*compilation_units_)[key->first].get();
unit->Execute(); unit->Execute();
outstanding_units_.fetch_sub(1, std::memory_order_relaxed); outstanding_units_.fetch_sub(1, std::memory_order_relaxed);
if (delegate && delegate->ShouldYield()) return; if (delegate && delegate->ShouldYield()) return;
...@@ -3943,10 +3956,13 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module, ...@@ -3943,10 +3956,13 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
for (auto exp : module->export_table) { for (auto exp : module->export_table) {
if (exp.kind != kExternalFunction) continue; if (exp.kind != kExternalFunction) continue;
auto& function = module->functions[exp.index]; auto& function = module->functions[exp.index];
JSToWasmWrapperKey key(function.imported, *function.sig); uint32_t canonical_type_index =
if (queue.insert(key)) { module->isorecursive_canonical_type_ids[function.sig_index];
JSToWasmWrapperKey key(function.imported, canonical_type_index);
if (queue.insert(key, nullptr)) {
auto unit = std::make_unique<JSToWasmWrapperCompilationUnit>( auto unit = std::make_unique<JSToWasmWrapperCompilationUnit>(
isolate, function.sig, module, function.imported, enabled_features, isolate, function.sig, canonical_type_index, module,
function.imported, enabled_features,
JSToWasmWrapperCompilationUnit::kAllowGeneric); JSToWasmWrapperCompilationUnit::kAllowGeneric);
compilation_units.emplace(key, std::move(unit)); compilation_units.emplace(key, std::move(unit));
} }
...@@ -3981,7 +3997,7 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module, ...@@ -3981,7 +3997,7 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
JSToWasmWrapperCompilationUnit* unit = pair.second.get(); JSToWasmWrapperCompilationUnit* unit = pair.second.get();
DCHECK_EQ(isolate, unit->isolate()); DCHECK_EQ(isolate, unit->isolate());
Handle<CodeT> code = unit->Finalize(); Handle<CodeT> code = unit->Finalize();
int wrapper_index = GetExportWrapperIndex(module, &key.second, key.first); int wrapper_index = GetExportWrapperIndex(module, key.second, key.first);
(*export_wrappers_out)->set(wrapper_index, *code); (*export_wrappers_out)->set(wrapper_index, *code);
RecordStats(*code, isolate->counters()); RecordStats(*code, isolate->counters());
} }
...@@ -3990,12 +4006,13 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module, ...@@ -3990,12 +4006,13 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
WasmCode* CompileImportWrapper( WasmCode* CompileImportWrapper(
NativeModule* native_module, Counters* counters, NativeModule* native_module, Counters* counters,
compiler::WasmImportCallKind kind, const FunctionSig* sig, compiler::WasmImportCallKind kind, const FunctionSig* sig,
int expected_arity, Suspend suspend, uint32_t canonical_type_index, int expected_arity, Suspend suspend,
WasmImportWrapperCache::ModificationScope* cache_scope) { WasmImportWrapperCache::ModificationScope* cache_scope) {
// Entry should exist, so that we don't insert a new one and invalidate // Entry should exist, so that we don't insert a new one and invalidate
// other threads' iterators/references, but it should not have been compiled // other threads' iterators/references, but it should not have been compiled
// yet. // yet.
WasmImportWrapperCache::CacheKey key(kind, sig, expected_arity, suspend); WasmImportWrapperCache::CacheKey key(kind, canonical_type_index,
expected_arity, suspend);
DCHECK_NULL((*cache_scope)[key]); DCHECK_NULL((*cache_scope)[key]);
bool source_positions = is_asmjs_module(native_module->module()); bool source_positions = is_asmjs_module(native_module->module());
// Keep the {WasmCode} alive until we explicitly call {IncRef}. // Keep the {WasmCode} alive until we explicitly call {IncRef}.
......
...@@ -74,7 +74,7 @@ V8_EXPORT_PRIVATE ...@@ -74,7 +74,7 @@ V8_EXPORT_PRIVATE
WasmCode* CompileImportWrapper( WasmCode* CompileImportWrapper(
NativeModule* native_module, Counters* counters, NativeModule* native_module, Counters* counters,
compiler::WasmImportCallKind kind, const FunctionSig* sig, compiler::WasmImportCallKind kind, const FunctionSig* sig,
int expected_arity, Suspend suspend, uint32_t canonical_type_index, int expected_arity, Suspend suspend,
WasmImportWrapperCache::ModificationScope* cache_scope); WasmImportWrapperCache::ModificationScope* cache_scope);
// Triggered by the WasmCompileLazy builtin. The return value indicates whether // Triggered by the WasmCompileLazy builtin. The return value indicates whether
...@@ -96,14 +96,14 @@ V8_EXPORT_PRIVATE void TriggerTierUp(WasmInstanceObject instance, ...@@ -96,14 +96,14 @@ V8_EXPORT_PRIVATE void TriggerTierUp(WasmInstanceObject instance,
void TierUpNowForTesting(Isolate* isolate, WasmInstanceObject instance, void TierUpNowForTesting(Isolate* isolate, WasmInstanceObject instance,
int func_index); int func_index);
template <typename Key, typename Hash> template <typename Key, typename KeyInfo, typename Hash>
class WrapperQueue { class WrapperQueue {
public: public:
// Removes an arbitrary key from the queue and returns it. // Removes an arbitrary key from the queue and returns it.
// If the queue is empty, returns nullopt. // If the queue is empty, returns nullopt.
// Thread-safe. // Thread-safe.
base::Optional<Key> pop() { base::Optional<std::pair<Key, KeyInfo>> pop() {
base::Optional<Key> key = base::nullopt; base::Optional<std::pair<Key, KeyInfo>> key = base::nullopt;
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
auto it = queue_.begin(); auto it = queue_.begin();
if (it != queue_.end()) { if (it != queue_.end()) {
...@@ -116,7 +116,9 @@ class WrapperQueue { ...@@ -116,7 +116,9 @@ class WrapperQueue {
// Add the given key to the queue and returns true iff the insert was // Add the given key to the queue and returns true iff the insert was
// successful. // successful.
// Not thread-safe. // Not thread-safe.
bool insert(const Key& key) { return queue_.insert(key).second; } bool insert(const Key& key, KeyInfo key_info) {
return queue_.insert({key, key_info}).second;
}
size_t size() { size_t size() {
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
...@@ -125,7 +127,7 @@ class WrapperQueue { ...@@ -125,7 +127,7 @@ class WrapperQueue {
private: private:
base::Mutex mutex_; base::Mutex mutex_;
std::unordered_set<Key, Hash> queue_; std::unordered_map<Key, KeyInfo, Hash> queue_;
}; };
// Encapsulates all the state and steps of an asynchronous compilation. // Encapsulates all the state and steps of an asynchronous compilation.
......
...@@ -684,9 +684,7 @@ class ModuleDecoderTemplate : public Decoder { ...@@ -684,9 +684,7 @@ class ModuleDecoderTemplate : public Decoder {
const FunctionSig* sig = consume_sig(module_->signature_zone.get()); const FunctionSig* sig = consume_sig(module_->signature_zone.get());
if (!ok()) break; if (!ok()) break;
module_->add_signature(sig, kNoSuperType); module_->add_signature(sig, kNoSuperType);
if (v8_flags.wasm_type_canonicalization) {
type_canon->AddRecursiveGroup(module_.get(), 1); type_canon->AddRecursiveGroup(module_.get(), 1);
}
break; break;
} }
case kWasmArrayTypeCode: case kWasmArrayTypeCode:
...@@ -727,20 +725,16 @@ class ModuleDecoderTemplate : public Decoder { ...@@ -727,20 +725,16 @@ class ModuleDecoderTemplate : public Decoder {
TypeDefinition type = consume_subtype_definition(); TypeDefinition type = consume_subtype_definition();
if (ok()) module_->add_type(type); if (ok()) module_->add_type(type);
} }
if (ok() && v8_flags.wasm_type_canonicalization) { if (ok()) type_canon->AddRecursiveGroup(module_.get(), group_size);
type_canon->AddRecursiveGroup(module_.get(), group_size);
}
} else { } else {
tracer_.TypeOffset(pc_offset()); tracer_.TypeOffset(pc_offset());
TypeDefinition type = consume_subtype_definition(); TypeDefinition type = consume_subtype_definition();
if (ok()) { if (ok()) {
module_->add_type(type); module_->add_type(type);
if (v8_flags.wasm_type_canonicalization) {
type_canon->AddRecursiveGroup(module_.get(), 1); type_canon->AddRecursiveGroup(module_.get(), 1);
} }
} }
} }
}
// Check validity of explicitly defined supertypes. // Check validity of explicitly defined supertypes.
const WasmModule* module = module_.get(); const WasmModule* module = module_.get();
......
...@@ -42,7 +42,8 @@ byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) { ...@@ -42,7 +42,8 @@ byte* raw_buffer_ptr(MaybeHandle<JSArrayBuffer> buffer, int offset) {
return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset; return static_cast<byte*>(buffer.ToHandleChecked()->backing_store()) + offset;
} }
using ImportWrapperQueue = WrapperQueue<WasmImportWrapperCache::CacheKey, using ImportWrapperQueue =
WrapperQueue<WasmImportWrapperCache::CacheKey, const FunctionSig*,
WasmImportWrapperCache::CacheKeyHash>; WasmImportWrapperCache::CacheKeyHash>;
class CompileImportWrapperJob final : public JobTask { class CompileImportWrapperJob final : public JobTask {
...@@ -66,12 +67,15 @@ class CompileImportWrapperJob final : public JobTask { ...@@ -66,12 +67,15 @@ class CompileImportWrapperJob final : public JobTask {
void Run(JobDelegate* delegate) override { void Run(JobDelegate* delegate) override {
TRACE_EVENT0("v8.wasm", "wasm.CompileImportWrapperJob.Run"); TRACE_EVENT0("v8.wasm", "wasm.CompileImportWrapperJob.Run");
while (base::Optional<WasmImportWrapperCache::CacheKey> key = while (base::Optional<std::pair<const WasmImportWrapperCache::CacheKey,
queue_->pop()) { const FunctionSig*>>
key = queue_->pop()) {
// TODO(wasm): Batch code publishing, to avoid repeated locking and // TODO(wasm): Batch code publishing, to avoid repeated locking and
// permission switching. // permission switching.
CompileImportWrapper(native_module_, counters_, key->kind, key->signature, CompileImportWrapper(native_module_, counters_, key->first.kind,
key->expected_arity, key->suspend, cache_scope_); key->second, key->first.canonical_type_index,
key->first.expected_arity, key->first.suspend,
cache_scope_);
if (delegate->ShouldYield()) return; if (delegate->ShouldYield()) return;
} }
} }
...@@ -828,9 +832,13 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() { ...@@ -828,9 +832,13 @@ MaybeHandle<WasmInstanceObject> InstanceBuilder::Build() {
if (module_->start_function_index >= 0) { if (module_->start_function_index >= 0) {
int start_index = module_->start_function_index; int start_index = module_->start_function_index;
auto& function = module_->functions[start_index]; auto& function = module_->functions[start_index];
uint32_t canonical_sig_index =
module_->isorecursive_canonical_type_ids[module_->functions[start_index]
.sig_index];
Handle<CodeT> wrapper_code = Handle<CodeT> wrapper_code =
JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper( JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
isolate_, function.sig, module_, function.imported); isolate_, function.sig, canonical_sig_index, module_,
function.imported);
// TODO(clemensb): Don't generate an exported function for the start // TODO(clemensb): Don't generate an exported function for the start
// function. Use CWasmEntry instead. // function. Use CWasmEntry instead.
start_function_ = WasmExportedFunction::New( start_function_ = WasmExportedFunction::New(
...@@ -1158,15 +1166,18 @@ bool InstanceBuilder::ProcessImportedFunction( ...@@ -1158,15 +1166,18 @@ bool InstanceBuilder::ProcessImportedFunction(
WasmImportWrapperCache* cache = native_module->import_wrapper_cache(); WasmImportWrapperCache* cache = native_module->import_wrapper_cache();
// TODO(jkummerow): Consider precompiling CapiCallWrappers in parallel, // TODO(jkummerow): Consider precompiling CapiCallWrappers in parallel,
// just like other import wrappers. // just like other import wrappers.
WasmCode* wasm_code = uint32_t canonical_type_index =
cache->MaybeGet(kind, expected_sig, expected_arity, kNoSuspend); module_->isorecursive_canonical_type_ids
[module_->functions[func_index].sig_index];
WasmCode* wasm_code = cache->MaybeGet(kind, canonical_type_index,
expected_arity, kNoSuspend);
if (wasm_code == nullptr) { if (wasm_code == nullptr) {
WasmCodeRefScope code_ref_scope; WasmCodeRefScope code_ref_scope;
WasmImportWrapperCache::ModificationScope cache_scope(cache); WasmImportWrapperCache::ModificationScope cache_scope(cache);
wasm_code = wasm_code =
compiler::CompileWasmCapiCallWrapper(native_module, expected_sig); compiler::CompileWasmCapiCallWrapper(native_module, expected_sig);
WasmImportWrapperCache::CacheKey key(kind, expected_sig, expected_arity, WasmImportWrapperCache::CacheKey key(kind, canonical_type_index,
kNoSuspend); expected_arity, kNoSuspend);
cache_scope[key] = wasm_code; cache_scope[key] = wasm_code;
wasm_code->IncRef(); wasm_code->IncRef();
isolate_->counters()->wasm_generated_code_size()->Increment( isolate_->counters()->wasm_generated_code_size()->Increment(
...@@ -1203,8 +1214,11 @@ bool InstanceBuilder::ProcessImportedFunction( ...@@ -1203,8 +1214,11 @@ bool InstanceBuilder::ProcessImportedFunction(
} }
NativeModule* native_module = instance->module_object().native_module(); NativeModule* native_module = instance->module_object().native_module();
uint32_t canonical_type_index =
module_->isorecursive_canonical_type_ids
[module_->functions[func_index].sig_index];
WasmCode* wasm_code = native_module->import_wrapper_cache()->Get( WasmCode* wasm_code = native_module->import_wrapper_cache()->Get(
kind, expected_sig, expected_arity, resolved.suspend); kind, canonical_type_index, expected_arity, resolved.suspend);
DCHECK_NOT_NULL(wasm_code); DCHECK_NOT_NULL(wasm_code);
ImportedFunctionEntry entry(instance, func_index); ImportedFunctionEntry entry(instance, func_index);
if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) { if (wasm_code->kind() == WasmCode::kWasmToJsWrapper) {
...@@ -1614,14 +1628,16 @@ void InstanceBuilder::CompileImportWrappers( ...@@ -1614,14 +1628,16 @@ void InstanceBuilder::CompileImportWrappers(
expected_arity = expected_arity =
shared.internal_formal_parameter_count_without_receiver(); shared.internal_formal_parameter_count_without_receiver();
} }
uint32_t canonical_type_index =
WasmImportWrapperCache::CacheKey key(kind, sig, expected_arity, module_->isorecursive_canonical_type_ids[module_->functions[func_index]
resolved.suspend); .sig_index];
WasmImportWrapperCache::CacheKey key(kind, canonical_type_index,
expected_arity, resolved.suspend);
if (cache_scope[key] != nullptr) { if (cache_scope[key] != nullptr) {
// Cache entry already exists, no need to compile it again. // Cache entry already exists, no need to compile it again.
continue; continue;
} }
import_wrapper_queue.insert(key); import_wrapper_queue.insert(key, sig);
} }
auto compile_job_task = std::make_unique<CompileImportWrapperJob>( auto compile_job_task = std::make_unique<CompileImportWrapperJob>(
......
...@@ -23,23 +23,25 @@ WasmCode*& WasmImportWrapperCache::operator[]( ...@@ -23,23 +23,25 @@ WasmCode*& WasmImportWrapperCache::operator[](
} }
WasmCode* WasmImportWrapperCache::Get(compiler::WasmImportCallKind kind, WasmCode* WasmImportWrapperCache::Get(compiler::WasmImportCallKind kind,
const FunctionSig* sig, uint32_t canonical_type_index,
int expected_arity, int expected_arity,
Suspend suspend) const { Suspend suspend) const {
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
auto it = entry_map_.find({kind, sig, expected_arity, suspend}); auto it =
entry_map_.find({kind, canonical_type_index, expected_arity, suspend});
DCHECK(it != entry_map_.end()); DCHECK(it != entry_map_.end());
return it->second; return it->second;
} }
WasmCode* WasmImportWrapperCache::MaybeGet(compiler::WasmImportCallKind kind, WasmCode* WasmImportWrapperCache::MaybeGet(compiler::WasmImportCallKind kind,
const FunctionSig* sig, uint32_t canonical_type_index,
int expected_arity, int expected_arity,
Suspend suspend) const { Suspend suspend) const {
base::MutexGuard lock(&mutex_); base::MutexGuard lock(&mutex_);
auto it = entry_map_.find({kind, sig, expected_arity, suspend}); auto it =
entry_map_.find({kind, canonical_type_index, expected_arity, suspend});
if (it == entry_map_.end()) return nullptr; if (it == entry_map_.end()) return nullptr;
return it->second; return it->second;
} }
......
...@@ -28,22 +28,23 @@ using FunctionSig = Signature<ValueType>; ...@@ -28,22 +28,23 @@ using FunctionSig = Signature<ValueType>;
class WasmImportWrapperCache { class WasmImportWrapperCache {
public: public:
struct CacheKey { struct CacheKey {
CacheKey(const compiler::WasmImportCallKind& _kind, const FunctionSig* _sig, CacheKey(const compiler::WasmImportCallKind& kind,
int _expected_arity, Suspend _suspend) uint32_t canonical_type_index, int expected_arity, Suspend suspend)
: kind(_kind), : kind(kind),
signature(_sig), canonical_type_index(canonical_type_index),
expected_arity(_expected_arity == kDontAdaptArgumentsSentinel expected_arity(expected_arity == kDontAdaptArgumentsSentinel
? 0 ? 0
: _expected_arity), : expected_arity),
suspend(_suspend) {} suspend(suspend) {}
bool operator==(const CacheKey& rhs) const { bool operator==(const CacheKey& rhs) const {
return kind == rhs.kind && signature == rhs.signature && return kind == rhs.kind &&
canonical_type_index == rhs.canonical_type_index &&
expected_arity == rhs.expected_arity && suspend == rhs.suspend; expected_arity == rhs.expected_arity && suspend == rhs.suspend;
} }
compiler::WasmImportCallKind kind; compiler::WasmImportCallKind kind;
const FunctionSig* signature; uint32_t canonical_type_index;
int expected_arity; int expected_arity;
Suspend suspend; Suspend suspend;
}; };
...@@ -51,8 +52,8 @@ class WasmImportWrapperCache { ...@@ -51,8 +52,8 @@ class WasmImportWrapperCache {
class CacheKeyHash { class CacheKeyHash {
public: public:
size_t operator()(const CacheKey& key) const { size_t operator()(const CacheKey& key) const {
return base::hash_combine(static_cast<uint8_t>(key.kind), key.signature, return base::hash_combine(static_cast<uint8_t>(key.kind),
key.expected_arity); key.canonical_type_index, key.expected_arity);
} }
}; };
...@@ -75,11 +76,12 @@ class WasmImportWrapperCache { ...@@ -75,11 +76,12 @@ class WasmImportWrapperCache {
// Thread-safe. Assumes the key exists in the map. // Thread-safe. Assumes the key exists in the map.
V8_EXPORT_PRIVATE WasmCode* Get(compiler::WasmImportCallKind kind, V8_EXPORT_PRIVATE WasmCode* Get(compiler::WasmImportCallKind kind,
const FunctionSig* sig, int expected_arity, uint32_t canonical_type_index,
Suspend suspend) const;
// Thread-safe. Returns nullptr if the key doesn't exist in the map.
WasmCode* MaybeGet(compiler::WasmImportCallKind kind, const FunctionSig* sig,
int expected_arity, Suspend suspend) const; int expected_arity, Suspend suspend) const;
// Thread-safe. Returns nullptr if the key doesn't exist in the map.
WasmCode* MaybeGet(compiler::WasmImportCallKind kind,
uint32_t canonical_type_index, int expected_arity,
Suspend suspend) const;
~WasmImportWrapperCache(); ~WasmImportWrapperCache();
......
...@@ -66,29 +66,19 @@ bool LazilyGeneratedNames::Has(uint32_t function_index) { ...@@ -66,29 +66,19 @@ bool LazilyGeneratedNames::Has(uint32_t function_index) {
// static // static
int MaxNumExportWrappers(const WasmModule* module) { int MaxNumExportWrappers(const WasmModule* module) {
// For each signature there may exist a wrapper, both for imported and if (module->isorecursive_canonical_type_ids.empty()) return 0;
// internal functions. // TODO(manoskouk): This will create oversized wrappers for modules with few
return static_cast<int>(module->signature_map.size()) * 2; // types but large canonical type indices. Move wrappers to isolate to avoid
} // this.
uint32_t max_canonical_index =
int GetExportWrapperIndexInternal(const WasmModule* module, *std::max_element(module->isorecursive_canonical_type_ids.begin(),
int canonical_sig_index, bool is_import) { module->isorecursive_canonical_type_ids.end());
if (is_import) canonical_sig_index += module->signature_map.size(); return (max_canonical_index + 1) * 2;
return canonical_sig_index; }
}
int GetExportWrapperIndex(const WasmModule* module,
int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig, uint32_t canonical_sig_index, bool is_import) {
bool is_import) { return 2 * canonical_sig_index + (is_import ? 1 : 0);
int canonical_sig_index = module->signature_map.Find(*sig);
CHECK_GE(canonical_sig_index, 0);
return GetExportWrapperIndexInternal(module, canonical_sig_index, is_import);
}
int GetExportWrapperIndex(const WasmModule* module, uint32_t sig_index,
bool is_import) {
uint32_t canonical_sig_index =
module->per_module_canonical_type_ids[sig_index];
return GetExportWrapperIndexInternal(module, canonical_sig_index, is_import);
} }
// static // static
......
...@@ -629,13 +629,11 @@ size_t EstimateStoredSize(const WasmModule* module); ...@@ -629,13 +629,11 @@ size_t EstimateStoredSize(const WasmModule* module);
// Returns the number of possible export wrappers for a given module. // Returns the number of possible export wrappers for a given module.
V8_EXPORT_PRIVATE int MaxNumExportWrappers(const WasmModule* module); V8_EXPORT_PRIVATE int MaxNumExportWrappers(const WasmModule* module);
// Returns the wrapper index for a function in {module} with signature {sig} // Returns the wrapper index for a function in {module} with isorecursive
// or {sig_index} and origin defined by {is_import}. // canonical signature index {canonical_sig_index}, and origin defined by
// Prefer to use the {sig_index} consuming version, as it is much faster. // {is_import}.
int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig, int GetExportWrapperIndex(const WasmModule* module,
bool is_import); uint32_t canonical_sig_index, bool is_import);
int GetExportWrapperIndex(const WasmModule* module, uint32_t sig_index,
bool is_import);
// Return the byte offset of the function identified by the given index. // Return the byte offset of the function identified by the given index.
// The offset will be relative to the start of the module bytes. // The offset will be relative to the start of the module bytes.
......
...@@ -548,14 +548,16 @@ void WasmTableObject::UpdateDispatchTables( ...@@ -548,14 +548,16 @@ void WasmTableObject::UpdateDispatchTables(
instance->module_object().native_module(); instance->module_object().native_module();
wasm::WasmImportWrapperCache* cache = native_module->import_wrapper_cache(); wasm::WasmImportWrapperCache* cache = native_module->import_wrapper_cache();
auto kind = compiler::WasmImportCallKind::kWasmToCapi; auto kind = compiler::WasmImportCallKind::kWasmToCapi;
wasm::WasmCode* wasm_code = uint32_t canonical_type_index =
cache->MaybeGet(kind, &sig, param_count, wasm::kNoSuspend); wasm::GetTypeCanonicalizer()->AddRecursiveGroup(&sig);
wasm::WasmCode* wasm_code = cache->MaybeGet(kind, canonical_type_index,
param_count, wasm::kNoSuspend);
if (wasm_code == nullptr) { if (wasm_code == nullptr) {
wasm::WasmCodeRefScope code_ref_scope; wasm::WasmCodeRefScope code_ref_scope;
wasm::WasmImportWrapperCache::ModificationScope cache_scope(cache); wasm::WasmImportWrapperCache::ModificationScope cache_scope(cache);
wasm_code = compiler::CompileWasmCapiCallWrapper(native_module, &sig); wasm_code = compiler::CompileWasmCapiCallWrapper(native_module, &sig);
wasm::WasmImportWrapperCache::CacheKey key(kind, &sig, param_count, wasm::WasmImportWrapperCache::CacheKey key(kind, canonical_type_index,
wasm::kNoSuspend); param_count, wasm::kNoSuspend);
cache_scope[key] = wasm_code; cache_scope[key] = wasm_code;
wasm_code->IncRef(); wasm_code->IncRef();
isolate->counters()->wasm_generated_code_size()->Increment( isolate->counters()->wasm_generated_code_size()->Increment(
...@@ -567,7 +569,9 @@ void WasmTableObject::UpdateDispatchTables( ...@@ -567,7 +569,9 @@ void WasmTableObject::UpdateDispatchTables(
// not found; it will simply never match any check. // not found; it will simply never match any check.
// It is safe to use this even when v8_flags.wasm_type_canonicalization, as // It is safe to use this even when v8_flags.wasm_type_canonicalization, as
// the C API cannot refer to user-defined types. // the C API cannot refer to user-defined types.
auto sig_id = instance->module()->signature_map.Find(sig); auto sig_id = v8_flags.wasm_type_canonicalization
? canonical_type_index
: instance->module()->signature_map.Find(sig);
instance->GetIndirectFunctionTable(isolate, table_index) instance->GetIndirectFunctionTable(isolate, table_index)
->Set(entry_index, sig_id, wasm_code->instruction_start(), ->Set(entry_index, sig_id, wasm_code->instruction_start(),
WasmCapiFunctionData::cast( WasmCapiFunctionData::cast(
...@@ -1379,10 +1383,10 @@ WasmInstanceObject::GetOrCreateWasmInternalFunction( ...@@ -1379,10 +1383,10 @@ WasmInstanceObject::GetOrCreateWasmInternalFunction(
Handle<WasmModuleObject> module_object(instance->module_object(), isolate); Handle<WasmModuleObject> module_object(instance->module_object(), isolate);
const WasmModule* module = module_object->module(); const WasmModule* module = module_object->module();
const WasmFunction& function = module->functions[function_index]; const WasmFunction& function = module->functions[function_index];
uint32_t canonical_sig_index =
module->isorecursive_canonical_type_ids[function.sig_index];
int wrapper_index = int wrapper_index =
GetExportWrapperIndex(module, function.sig_index, function.imported); GetExportWrapperIndex(module, canonical_sig_index, function.imported);
DCHECK_EQ(wrapper_index,
GetExportWrapperIndex(module, function.sig, function.imported));
Handle<Object> entry = Handle<Object> entry =
FixedArray::get(module_object->export_wrappers(), wrapper_index, isolate); FixedArray::get(module_object->export_wrappers(), wrapper_index, isolate);
...@@ -1395,7 +1399,8 @@ WasmInstanceObject::GetOrCreateWasmInternalFunction( ...@@ -1395,7 +1399,8 @@ WasmInstanceObject::GetOrCreateWasmInternalFunction(
// this signature. We compile it and store the wrapper in the module for // this signature. We compile it and store the wrapper in the module for
// later use. // later use.
wrapper = wasm::JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper( wrapper = wasm::JSToWasmWrapperCompilationUnit::CompileJSToWasmWrapper(
isolate, function.sig, instance->module(), function.imported); isolate, function.sig, canonical_sig_index, instance->module(),
function.imported);
module_object->export_wrappers().set(wrapper_index, *wrapper); module_object->export_wrappers().set(wrapper_index, *wrapper);
} }
auto external = Handle<WasmExternalFunction>::cast(WasmExportedFunction::New( auto external = Handle<WasmExternalFunction>::cast(WasmExportedFunction::New(
......
...@@ -77,11 +77,13 @@ extern class WasmExportedFunctionData extends WasmFunctionData { ...@@ -77,11 +77,13 @@ extern class WasmExportedFunctionData extends WasmFunctionData {
extern class WasmJSFunctionData extends WasmFunctionData { extern class WasmJSFunctionData extends WasmFunctionData {
serialized_return_count: Smi; serialized_return_count: Smi;
serialized_parameter_count: Smi; serialized_parameter_count: Smi;
// TODO(7748): Maybe store the canonical type index of the signature instead.
serialized_signature: PodArrayOfWasmValueType; serialized_signature: PodArrayOfWasmValueType;
} }
extern class WasmCapiFunctionData extends WasmFunctionData { extern class WasmCapiFunctionData extends WasmFunctionData {
embedder_data: Foreign; // Managed<wasm::FuncData> embedder_data: Foreign; // Managed<wasm::FuncData>
// TODO(7748): Maybe store the canonical type index of the signature instead.
serialized_signature: PodArrayOfWasmValueType; serialized_signature: PodArrayOfWasmValueType;
} }
......
...@@ -37,16 +37,19 @@ TEST(CacheHit) { ...@@ -37,16 +37,19 @@ TEST(CacheHit) {
auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch; auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch;
auto sig = sigs.i_i(); auto sig = sigs.i_i();
uint32_t canonical_type_index =
GetTypeCanonicalizer()->AddRecursiveGroup(sig);
int expected_arity = static_cast<int>(sig->parameter_count()); int expected_arity = static_cast<int>(sig->parameter_count());
WasmCode* c1 = WasmCode* c1 = CompileImportWrapper(module.get(), isolate->counters(), kind,
CompileImportWrapper(module.get(), isolate->counters(), kind, sig, sig, canonical_type_index, expected_arity,
expected_arity, kNoSuspend, &cache_scope); kNoSuspend, &cache_scope);
CHECK_NOT_NULL(c1); CHECK_NOT_NULL(c1);
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind()); CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
WasmCode* c2 = cache_scope[{kind, sig, expected_arity, kNoSuspend}]; WasmCode* c2 =
cache_scope[{kind, canonical_type_index, expected_arity, kNoSuspend}];
CHECK_NOT_NULL(c2); CHECK_NOT_NULL(c2);
CHECK_EQ(c1, c2); CHECK_EQ(c1, c2);
...@@ -63,17 +66,22 @@ TEST(CacheMissSig) { ...@@ -63,17 +66,22 @@ TEST(CacheMissSig) {
auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch; auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch;
auto sig1 = sigs.i_i(); auto sig1 = sigs.i_i();
int expected_arity1 = static_cast<int>(sig1->parameter_count()); int expected_arity1 = static_cast<int>(sig1->parameter_count());
uint32_t canonical_type_index1 =
GetTypeCanonicalizer()->AddRecursiveGroup(sig1);
auto sig2 = sigs.i_ii(); auto sig2 = sigs.i_ii();
int expected_arity2 = static_cast<int>(sig2->parameter_count()); int expected_arity2 = static_cast<int>(sig2->parameter_count());
uint32_t canonical_type_index2 =
GetTypeCanonicalizer()->AddRecursiveGroup(sig2);
WasmCode* c1 = WasmCode* c1 = CompileImportWrapper(
CompileImportWrapper(module.get(), isolate->counters(), kind, sig1, module.get(), isolate->counters(), kind, sig1, canonical_type_index1,
expected_arity1, kNoSuspend, &cache_scope); expected_arity1, kNoSuspend, &cache_scope);
CHECK_NOT_NULL(c1); CHECK_NOT_NULL(c1);
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind()); CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
WasmCode* c2 = cache_scope[{kind, sig2, expected_arity2, kNoSuspend}]; WasmCode* c2 =
cache_scope[{kind, canonical_type_index2, expected_arity2, kNoSuspend}];
CHECK_NULL(c2); CHECK_NULL(c2);
} }
...@@ -90,15 +98,18 @@ TEST(CacheMissKind) { ...@@ -90,15 +98,18 @@ TEST(CacheMissKind) {
auto kind2 = compiler::WasmImportCallKind::kJSFunctionArityMismatch; auto kind2 = compiler::WasmImportCallKind::kJSFunctionArityMismatch;
auto sig = sigs.i_i(); auto sig = sigs.i_i();
int expected_arity = static_cast<int>(sig->parameter_count()); int expected_arity = static_cast<int>(sig->parameter_count());
uint32_t canonical_type_index =
GetTypeCanonicalizer()->AddRecursiveGroup(sig);
WasmCode* c1 = WasmCode* c1 = CompileImportWrapper(module.get(), isolate->counters(), kind1,
CompileImportWrapper(module.get(), isolate->counters(), kind1, sig, sig, canonical_type_index, expected_arity,
expected_arity, kNoSuspend, &cache_scope); kNoSuspend, &cache_scope);
CHECK_NOT_NULL(c1); CHECK_NOT_NULL(c1);
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind()); CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
WasmCode* c2 = cache_scope[{kind2, sig, expected_arity, kNoSuspend}]; WasmCode* c2 =
cache_scope[{kind2, canonical_type_index, expected_arity, kNoSuspend}];
CHECK_NULL(c2); CHECK_NULL(c2);
} }
...@@ -114,31 +125,39 @@ TEST(CacheHitMissSig) { ...@@ -114,31 +125,39 @@ TEST(CacheHitMissSig) {
auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch; auto kind = compiler::WasmImportCallKind::kJSFunctionArityMatch;
auto sig1 = sigs.i_i(); auto sig1 = sigs.i_i();
int expected_arity1 = static_cast<int>(sig1->parameter_count()); int expected_arity1 = static_cast<int>(sig1->parameter_count());
uint32_t canonical_type_index1 =
GetTypeCanonicalizer()->AddRecursiveGroup(sig1);
auto sig2 = sigs.i_ii(); auto sig2 = sigs.i_ii();
int expected_arity2 = static_cast<int>(sig2->parameter_count()); int expected_arity2 = static_cast<int>(sig2->parameter_count());
uint32_t canonical_type_index2 =
GetTypeCanonicalizer()->AddRecursiveGroup(sig2);
WasmCode* c1 = WasmCode* c1 = CompileImportWrapper(
CompileImportWrapper(module.get(), isolate->counters(), kind, sig1, module.get(), isolate->counters(), kind, sig1, canonical_type_index1,
expected_arity1, kNoSuspend, &cache_scope); expected_arity1, kNoSuspend, &cache_scope);
CHECK_NOT_NULL(c1); CHECK_NOT_NULL(c1);
CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind()); CHECK_EQ(WasmCode::Kind::kWasmToJsWrapper, c1->kind());
WasmCode* c2 = cache_scope[{kind, sig2, expected_arity2, kNoSuspend}]; WasmCode* c2 =
cache_scope[{kind, canonical_type_index2, expected_arity2, kNoSuspend}];
CHECK_NULL(c2); CHECK_NULL(c2);
c2 = CompileImportWrapper(module.get(), isolate->counters(), kind, sig2, c2 = CompileImportWrapper(module.get(), isolate->counters(), kind, sig2,
expected_arity2, kNoSuspend, &cache_scope); canonical_type_index2, expected_arity2, kNoSuspend,
&cache_scope);
CHECK_NE(c1, c2); CHECK_NE(c1, c2);
WasmCode* c3 = cache_scope[{kind, sig1, expected_arity1, kNoSuspend}]; WasmCode* c3 =
cache_scope[{kind, canonical_type_index1, expected_arity1, kNoSuspend}];
CHECK_NOT_NULL(c3); CHECK_NOT_NULL(c3);
CHECK_EQ(c1, c3); CHECK_EQ(c1, c3);
WasmCode* c4 = cache_scope[{kind, sig2, expected_arity2, kNoSuspend}]; WasmCode* c4 =
cache_scope[{kind, canonical_type_index2, expected_arity2, kNoSuspend}];
CHECK_NOT_NULL(c4); CHECK_NOT_NULL(c4);
CHECK_EQ(c2, c4); CHECK_EQ(c2, c4);
......
...@@ -82,14 +82,17 @@ TestingModuleBuilder::TestingModuleBuilder( ...@@ -82,14 +82,17 @@ TestingModuleBuilder::TestingModuleBuilder(
Handle<JSReceiver> callable = resolved.callable; Handle<JSReceiver> callable = resolved.callable;
WasmImportWrapperCache::ModificationScope cache_scope( WasmImportWrapperCache::ModificationScope cache_scope(
native_module_->import_wrapper_cache()); native_module_->import_wrapper_cache());
uint32_t canonical_type_index =
GetTypeCanonicalizer()->AddRecursiveGroup(maybe_import->sig);
WasmImportWrapperCache::CacheKey key( WasmImportWrapperCache::CacheKey key(
kind, maybe_import->sig, kind, canonical_type_index,
static_cast<int>(maybe_import->sig->parameter_count()), kNoSuspend); static_cast<int>(maybe_import->sig->parameter_count()), kNoSuspend);
auto import_wrapper = cache_scope[key]; auto import_wrapper = cache_scope[key];
if (import_wrapper == nullptr) { if (import_wrapper == nullptr) {
CodeSpaceWriteScope write_scope(native_module_); CodeSpaceWriteScope write_scope(native_module_);
import_wrapper = CompileImportWrapper( import_wrapper = CompileImportWrapper(
native_module_, isolate_->counters(), kind, maybe_import->sig, native_module_, isolate_->counters(), kind, maybe_import->sig,
canonical_type_index,
static_cast<int>(maybe_import->sig->parameter_count()), kNoSuspend, static_cast<int>(maybe_import->sig->parameter_count()), kNoSuspend,
&cache_scope); &cache_scope);
} }
......
...@@ -138,8 +138,8 @@ class TestingModuleBuilder { ...@@ -138,8 +138,8 @@ class TestingModuleBuilder {
DCHECK_EQ(test_module_->types.size(), DCHECK_EQ(test_module_->types.size(),
test_module_->per_module_canonical_type_ids.size()); test_module_->per_module_canonical_type_ids.size());
test_module_->add_signature(sig, kNoSuperType); test_module_->add_signature(sig, kNoSuperType);
if (v8_flags.wasm_type_canonicalization) {
GetTypeCanonicalizer()->AddRecursiveGroup(test_module_.get(), 1); GetTypeCanonicalizer()->AddRecursiveGroup(test_module_.get(), 1);
if (v8_flags.wasm_type_canonicalization) {
instance_object_->set_isorecursive_canonical_types( instance_object_->set_isorecursive_canonical_types(
test_module_->isorecursive_canonical_type_ids.data()); test_module_->isorecursive_canonical_type_ids.data());
} }
......
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