Commit d56ee2e3 authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm][anyref] Cache export wrappers per signature

Up until now, we cached export wrappers per export index. With the
anyref proposal potentially many more functions will need export
wrappers, e.g. any function that is stored in a table, and any
function accessed by the new ref.func instruction.

With this CL, we change the caching scheme an do the caching per
signature. Thereby we can guarantee that any export wrapper which
potentially exists can be stored in the cache.

For cctests which use wasm-run-utils, we don't know the size of the
cache anymore ahead of time. However, we assume that no more than
5 signatures will be used in any cctest. If this assumption is not
true, we can just adjust the number.

The cache is now accessed in all code paths where we need an export
wrapper.

Bug: chromium:962850

Change-Id: I32df60dfa7801d1e71f7d837da091f388198af1f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1615247
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61752}
parent 4088c521
...@@ -1076,8 +1076,6 @@ std::shared_ptr<NativeModule> CompileToNativeModule( ...@@ -1076,8 +1076,6 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
if (wasm_module->has_shared_memory) { if (wasm_module->has_shared_memory) {
isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory); isolate->CountUsage(v8::Isolate::UseCounterFeature::kWasmSharedMemory);
} }
int export_wrapper_size = static_cast<int>(module->num_exported_functions);
// TODO(wasm): only save the sections necessary to deserialize a // TODO(wasm): only save the sections necessary to deserialize a
// {WasmModule}. E.g. function bodies could be omitted. // {WasmModule}. E.g. function bodies could be omitted.
OwnedVector<uint8_t> wire_bytes_copy = OwnedVector<uint8_t> wire_bytes_copy =
...@@ -1098,8 +1096,9 @@ std::shared_ptr<NativeModule> CompileToNativeModule( ...@@ -1098,8 +1096,9 @@ std::shared_ptr<NativeModule> CompileToNativeModule(
if (thrower->error()) return {}; if (thrower->error()) return {};
// Compile JS->wasm wrappers for exported functions. // Compile JS->wasm wrappers for exported functions.
*export_wrappers_out = isolate->factory()->NewFixedArray( int num_wrappers = MaxNumExportWrappers(native_module->module());
export_wrapper_size, AllocationType::kOld); *export_wrappers_out =
isolate->factory()->NewFixedArray(num_wrappers, AllocationType::kOld);
CompileJsToWasmWrappers(isolate, native_module->module(), CompileJsToWasmWrappers(isolate, native_module->module(),
*export_wrappers_out); *export_wrappers_out);
...@@ -2186,7 +2185,6 @@ void CompilationStateImpl::SetError() { ...@@ -2186,7 +2185,6 @@ void CompilationStateImpl::SetError() {
void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module, void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
Handle<FixedArray> export_wrappers) { Handle<FixedArray> export_wrappers) {
JSToWasmWrapperCache js_to_wasm_cache; JSToWasmWrapperCache js_to_wasm_cache;
int wrapper_index = 0;
// TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an // TODO(6792): Wrappers below are allocated with {Factory::NewCode}. As an
// optimization we keep the code space unlocked to avoid repeated unlocking // optimization we keep the code space unlocked to avoid repeated unlocking
...@@ -2197,9 +2195,11 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module, ...@@ -2197,9 +2195,11 @@ void CompileJsToWasmWrappers(Isolate* isolate, const WasmModule* module,
auto& function = module->functions[exp.index]; auto& function = module->functions[exp.index];
Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper( Handle<Code> wrapper_code = js_to_wasm_cache.GetOrCompileJSToWasmWrapper(
isolate, function.sig, function.imported); isolate, function.sig, function.imported);
int wrapper_index =
GetExportWrapperIndex(module, function.sig, function.imported);
export_wrappers->set(wrapper_index, *wrapper_code); export_wrappers->set(wrapper_index, *wrapper_code);
RecordStats(*wrapper_code, isolate->counters()); RecordStats(*wrapper_code, isolate->counters());
++wrapper_index;
} }
} }
......
...@@ -1316,8 +1316,6 @@ bool InstanceBuilder::NeedsWrappers() const { ...@@ -1316,8 +1316,6 @@ bool InstanceBuilder::NeedsWrappers() const {
// Process the exports, creating wrappers for functions, tables, memories, // Process the exports, creating wrappers for functions, tables, memories,
// globals, and exceptions. // globals, and exceptions.
void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) { void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
Handle<FixedArray> export_wrappers(module_object_->export_wrappers(),
isolate_);
if (NeedsWrappers()) { if (NeedsWrappers()) {
// If an imported WebAssembly function gets exported, the exported function // If an imported WebAssembly function gets exported, the exported function
// has to be identical to to imported function. Therefore we cache all // has to be identical to to imported function. Therefore we cache all
...@@ -1365,7 +1363,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) { ...@@ -1365,7 +1363,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
desc.set_configurable(is_asm_js); desc.set_configurable(is_asm_js);
// Process each export in the export table. // Process each export in the export table.
int export_index = 0; // Index into {export_wrappers}.
for (const WasmExport& exp : module_->export_table) { for (const WasmExport& exp : module_->export_table) {
Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes( Handle<String> name = WasmModuleObject::ExtractUtf8StringFromModuleBytes(
isolate_, module_object_, exp.name) isolate_, module_object_, exp.name)
...@@ -1387,7 +1384,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) { ...@@ -1387,7 +1384,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
isolate_, instance, exp.index); isolate_, instance, exp.index);
desc.set_value(wasm_exported_function.ToHandleChecked()); desc.set_value(wasm_exported_function.ToHandleChecked());
export_index++;
break; break;
} }
case kExternalTable: { case kExternalTable: {
...@@ -1483,7 +1479,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) { ...@@ -1483,7 +1479,6 @@ void InstanceBuilder::ProcessExports(Handle<WasmInstanceObject> instance) {
return; return;
} }
} }
DCHECK_EQ(export_index, export_wrappers->length());
if (module_->origin == kWasmOrigin) { if (module_->origin == kWasmOrigin) {
v8::Maybe<bool> success = v8::Maybe<bool> success =
......
...@@ -34,6 +34,10 @@ class V8_EXPORT_PRIVATE SignatureMap { ...@@ -34,6 +34,10 @@ class V8_EXPORT_PRIVATE SignatureMap {
// Disallows further insertions to this signature map. // Disallows further insertions to this signature map.
void Freeze() { frozen_ = true; } void Freeze() { frozen_ = true; }
size_t size() const { return map_.size(); }
bool is_frozen() const { return frozen_; }
private: private:
bool frozen_ = false; bool frozen_ = false;
std::unordered_map<FunctionSig, uint32_t, base::hash<FunctionSig>> map_; std::unordered_map<FunctionSig, uint32_t, base::hash<FunctionSig>> map_;
......
...@@ -42,6 +42,22 @@ WireBytesRef WasmModule::LookupFunctionName(const ModuleWireBytes& wire_bytes, ...@@ -42,6 +42,22 @@ WireBytesRef WasmModule::LookupFunctionName(const ModuleWireBytes& wire_bytes,
return it->second; return it->second;
} }
// static
int MaxNumExportWrappers(const WasmModule* module) {
// For each signature there may exist a wrapper, both for imported and
// internal functions.
return static_cast<int>(module->signature_map.size()) * 2;
}
// static
int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig,
bool is_import) {
int result = module->signature_map.Find(*sig);
CHECK_GE(result, 0);
result += is_import ? module->signature_map.size() : 0;
return result;
}
void WasmModule::AddFunctionNameForTesting(int function_index, void WasmModule::AddFunctionNameForTesting(int function_index,
WireBytesRef name) { WireBytesRef name) {
if (!function_names) { if (!function_names) {
......
...@@ -223,6 +223,14 @@ struct V8_EXPORT_PRIVATE WasmModule { ...@@ -223,6 +223,14 @@ struct V8_EXPORT_PRIVATE WasmModule {
size_t EstimateStoredSize(const WasmModule* module); size_t EstimateStoredSize(const WasmModule* module);
// Returns the number of possible export wrappers for a given module.
V8_EXPORT_PRIVATE int MaxNumExportWrappers(const WasmModule* module);
// Returns the wrapper index for a function in {module} with signature {sig}
// and origin defined by {is_import}.
int GetExportWrapperIndex(const WasmModule* module, const FunctionSig* sig,
bool is_import);
// Interface to the storage (wire bytes) of a wasm module. // Interface to the storage (wire bytes) of a wasm module.
// It is illegal for anyone receiving a ModuleWireBytes to store pointers based // It is illegal for anyone receiving a ModuleWireBytes to store pointers based
// on module_bytes, as this storage is only guaranteed to be alive as long as // on module_bytes, as this storage is only guaranteed to be alive as long as
......
...@@ -232,9 +232,9 @@ Handle<WasmModuleObject> WasmModuleObject::New( ...@@ -232,9 +232,9 @@ Handle<WasmModuleObject> WasmModuleObject::New(
Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module, Isolate* isolate, std::shared_ptr<wasm::NativeModule> native_module,
Handle<Script> script, size_t code_size_estimate) { Handle<Script> script, size_t code_size_estimate) {
const WasmModule* module = native_module->module(); const WasmModule* module = native_module->module();
int export_wrapper_size = static_cast<int>(module->num_exported_functions); int num_wrappers = MaxNumExportWrappers(module);
Handle<FixedArray> export_wrappers = isolate->factory()->NewFixedArray( Handle<FixedArray> export_wrappers =
export_wrapper_size, AllocationType::kOld); isolate->factory()->NewFixedArray(num_wrappers, AllocationType::kOld);
return New(isolate, std::move(native_module), script, export_wrappers, return New(isolate, std::move(native_module), script, export_wrappers,
code_size_estimate); code_size_estimate);
} }
...@@ -1814,15 +1814,30 @@ WasmInstanceObject::GetOrCreateWasmExportedFunction( ...@@ -1814,15 +1814,30 @@ WasmInstanceObject::GetOrCreateWasmExportedFunction(
return result; return result;
} }
const WasmModule* module = instance->module_object()->module(); Handle<WasmModuleObject> module_object(instance->module_object(), isolate);
const WasmModule* module = module_object->module();
const WasmFunction& function = module->functions[function_index]; const WasmFunction& function = module->functions[function_index];
Handle<Code> wrapper_code = int wrapper_index =
compiler::CompileJSToWasmWrapper(isolate, function.sig, function.imported) GetExportWrapperIndex(module, function.sig, function.imported);
.ToHandleChecked();
Handle<Object> entry =
FixedArray::get(module_object->export_wrappers(), wrapper_index, isolate);
Handle<Code> wrapper;
if (entry->IsCode()) {
wrapper = Handle<Code>::cast(entry);
} else {
// The wrapper may not exist yet if no function in the exports section has
// this signature. We compile it and store the wrapper in the module for
// later use.
wrapper = compiler::CompileJSToWasmWrapper(isolate, function.sig,
function.imported)
.ToHandleChecked();
module_object->export_wrappers()->set(wrapper_index, *wrapper);
}
result = WasmExportedFunction::New( result = WasmExportedFunction::New(
isolate, instance, function_index, isolate, instance, function_index,
static_cast<int>(function.sig->parameter_count()), wrapper_code); static_cast<int>(function.sig->parameter_count()), wrapper);
WasmInstanceObject::SetWasmExportedFunction(isolate, instance, function_index, WasmInstanceObject::SetWasmExportedFunction(isolate, instance, function_index,
result); result);
......
...@@ -587,8 +587,9 @@ class WasmInstanceObject : public JSObject { ...@@ -587,8 +587,9 @@ class WasmInstanceObject : public JSObject {
// cache of the given {instance}, or creates a new {WasmExportedFunction} if // cache of the given {instance}, or creates a new {WasmExportedFunction} if
// it does not exist yet. The new {WasmExportedFunction} is added to the // it does not exist yet. The new {WasmExportedFunction} is added to the
// cache of the {instance} immediately. // cache of the {instance} immediately.
static Handle<WasmExportedFunction> GetOrCreateWasmExportedFunction( V8_EXPORT_PRIVATE static Handle<WasmExportedFunction>
Isolate* isolate, Handle<WasmInstanceObject> instance, GetOrCreateWasmExportedFunction(Isolate* isolate,
Handle<WasmInstanceObject> instance,
int function_index); int function_index);
static void SetWasmExportedFunction(Isolate* isolate, static void SetWasmExportedFunction(Isolate* isolate,
......
...@@ -543,6 +543,8 @@ WASM_EXEC_TEST(TableCopyElems) { ...@@ -543,6 +543,8 @@ WASM_EXEC_TEST(TableCopyElems) {
WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)), WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
kExprI32Const, 0); kExprI32Const, 0);
r.builder().FreezeSignatureMapAndInitializeWrapperCache();
auto table = handle( auto table = handle(
WasmTableObject::cast(r.builder().instance_object()->tables().get(0)), WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
isolate); isolate);
...@@ -628,6 +630,8 @@ WASM_EXEC_TEST(TableCopyOobWrites) { ...@@ -628,6 +630,8 @@ WASM_EXEC_TEST(TableCopyOobWrites) {
WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)), WASM_TABLE_COPY(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), WASM_GET_LOCAL(2)),
kExprI32Const, 0); kExprI32Const, 0);
r.builder().FreezeSignatureMapAndInitializeWrapperCache();
auto table = handle( auto table = handle(
WasmTableObject::cast(r.builder().instance_object()->tables().get(0)), WasmTableObject::cast(r.builder().instance_object()->tables().get(0)),
isolate); isolate);
......
...@@ -71,7 +71,7 @@ WASM_EXEC_TEST(TryCatchCallIndirect) { ...@@ -71,7 +71,7 @@ WASM_EXEC_TEST(TryCatchCallIndirect) {
// Build a throwing helper function. // Build a throwing helper function.
WasmFunctionCompiler& throw_func = r.NewFunction(sigs.i_ii()); WasmFunctionCompiler& throw_func = r.NewFunction(sigs.i_ii());
BUILD(throw_func, WASM_THROW(except)); BUILD(throw_func, WASM_THROW(except));
r.builder().AddSignature(sigs.i_ii()); byte sig_index = r.builder().AddSignature(sigs.i_ii());
throw_func.SetSigIndex(0); throw_func.SetSigIndex(0);
// Add an indirect function table. // Add an indirect function table.
...@@ -86,7 +86,7 @@ WASM_EXEC_TEST(TryCatchCallIndirect) { ...@@ -86,7 +86,7 @@ WASM_EXEC_TEST(TryCatchCallIndirect) {
WASM_STMTS(WASM_I32V(kResult1), WASM_STMTS(WASM_I32V(kResult1),
WASM_IF(WASM_I32_EQZ(WASM_GET_LOCAL(0)), WASM_IF(WASM_I32_EQZ(WASM_GET_LOCAL(0)),
WASM_STMTS(WASM_CALL_INDIRECT2( WASM_STMTS(WASM_CALL_INDIRECT2(
0, WASM_GET_LOCAL(0), sig_index, WASM_GET_LOCAL(0),
WASM_I32V(7), WASM_I32V(9)), WASM_I32V(7), WASM_I32V(9)),
WASM_DROP))), WASM_DROP))),
WASM_STMTS(WASM_DROP, WASM_I32V(kResult0)))); WASM_STMTS(WASM_DROP, WASM_I32V(kResult0))));
......
...@@ -220,7 +220,7 @@ TEST(Run_Wasm_returnCallIndirectFactorial) { ...@@ -220,7 +220,7 @@ TEST(Run_Wasm_returnCallIndirectFactorial) {
WasmFunctionCompiler& fact_aux_fn = r.NewFunction(sigs.i_ii(), "fact_aux"); WasmFunctionCompiler& fact_aux_fn = r.NewFunction(sigs.i_ii(), "fact_aux");
fact_aux_fn.SetSigIndex(0); fact_aux_fn.SetSigIndex(0);
r.builder().AddSignature(sigs.i_ii()); byte sig_index = r.builder().AddSignature(sigs.i_ii());
// Function table. // Function table.
uint16_t indirect_function_table[] = { uint16_t indirect_function_table[] = {
...@@ -229,14 +229,15 @@ TEST(Run_Wasm_returnCallIndirectFactorial) { ...@@ -229,14 +229,15 @@ TEST(Run_Wasm_returnCallIndirectFactorial) {
r.builder().AddIndirectFunctionTable(indirect_function_table, r.builder().AddIndirectFunctionTable(indirect_function_table,
arraysize(indirect_function_table)); arraysize(indirect_function_table));
BUILD(r, WASM_RETURN_CALL_INDIRECT(0, WASM_I32V(0), WASM_GET_LOCAL(0), BUILD(r, WASM_RETURN_CALL_INDIRECT(sig_index, WASM_I32V(0), WASM_GET_LOCAL(0),
WASM_I32V(1))); WASM_I32V(1)));
BUILD(fact_aux_fn, BUILD(fact_aux_fn,
WASM_IF_ELSE_I( WASM_IF_ELSE_I(
WASM_I32_EQ(WASM_I32V(1), WASM_GET_LOCAL(0)), WASM_GET_LOCAL(1), WASM_I32_EQ(WASM_I32V(1), WASM_GET_LOCAL(0)), WASM_GET_LOCAL(1),
WASM_RETURN_CALL_INDIRECT( WASM_RETURN_CALL_INDIRECT(
0, WASM_I32V(0), WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_I32V(1)), sig_index, WASM_I32V(0),
WASM_I32_SUB(WASM_GET_LOCAL(0), WASM_I32V(1)),
WASM_I32_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1))))); WASM_I32_MUL(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)))));
uint32_t test_values[] = {1, 2, 5, 10, 20}; uint32_t test_values[] = {1, 2, 5, 10, 20};
......
...@@ -141,13 +141,14 @@ WASM_EXEC_TEST(Run_IndirectCallJSFunction) { ...@@ -141,13 +141,14 @@ WASM_EXEC_TEST(Run_IndirectCallJSFunction) {
WasmFunctionCompiler& rc_fn = r.NewFunction(sigs.i_i(), "rc"); WasmFunctionCompiler& rc_fn = r.NewFunction(sigs.i_i(), "rc");
r.builder().AddSignature(sigs.i_iii()); byte sig_index = r.builder().AddSignature(sigs.i_iii());
uint16_t indirect_function_table[] = {static_cast<uint16_t>(js_index)}; uint16_t indirect_function_table[] = {static_cast<uint16_t>(js_index)};
r.builder().AddIndirectFunctionTable(indirect_function_table, r.builder().AddIndirectFunctionTable(indirect_function_table,
arraysize(indirect_function_table)); arraysize(indirect_function_table));
BUILD(rc_fn, WASM_CALL_INDIRECT3(0, WASM_I32V(js_index), WASM_I32V(left), BUILD(rc_fn,
WASM_CALL_INDIRECT3(sig_index, WASM_I32V(js_index), WASM_I32V(left),
WASM_I32V(right), WASM_GET_LOCAL(0))); WASM_I32V(right), WASM_GET_LOCAL(0)));
Handle<Object> args_left[] = {isolate->factory()->NewNumber(1)}; Handle<Object> args_left[] = {isolate->factory()->NewNumber(1)};
...@@ -538,15 +539,15 @@ void RunPickerTest(ExecutionTier tier, bool indirect) { ...@@ -538,15 +539,15 @@ void RunPickerTest(ExecutionTier tier, bool indirect) {
WasmFunctionCompiler& rc_fn = r.NewFunction(sigs.i_i(), "rc"); WasmFunctionCompiler& rc_fn = r.NewFunction(sigs.i_i(), "rc");
if (indirect) { if (indirect) {
r.builder().AddSignature(sigs.i_iii()); byte sig_index = r.builder().AddSignature(sigs.i_iii());
uint16_t indirect_function_table[] = {static_cast<uint16_t>(js_index)}; uint16_t indirect_function_table[] = {static_cast<uint16_t>(js_index)};
r.builder().AddIndirectFunctionTable(indirect_function_table, r.builder().AddIndirectFunctionTable(indirect_function_table,
arraysize(indirect_function_table)); arraysize(indirect_function_table));
BUILD(rc_fn, BUILD(rc_fn, WASM_RETURN_CALL_INDIRECT(sig_index, WASM_I32V(js_index),
WASM_RETURN_CALL_INDIRECT(0, WASM_I32V(js_index), WASM_I32V(left), WASM_I32V(left), WASM_I32V(right),
WASM_I32V(right), WASM_GET_LOCAL(0))); WASM_GET_LOCAL(0)));
} else { } else {
BUILD(rc_fn, BUILD(rc_fn,
WASM_RETURN_CALL_FUNCTION(js_index, WASM_I32V(left), WASM_I32V(right), WASM_RETURN_CALL_FUNCTION(js_index, WASM_I32V(left), WASM_I32V(right),
......
...@@ -122,15 +122,14 @@ WASM_EXEC_TEST(Int32Add_P2) { ...@@ -122,15 +122,14 @@ WASM_EXEC_TEST(Int32Add_P2) {
WASM_EXEC_TEST(Int32Add_block1) { WASM_EXEC_TEST(Int32Add_block1) {
EXPERIMENTAL_FLAG_SCOPE(mv); EXPERIMENTAL_FLAG_SCOPE(mv);
static const byte code[] = { static const byte code[] = {
WASM_BLOCK_X(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)), WASM_BLOCK_X(1, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)), kExprI32Add};
kExprI32Add};
RunInt32AddTest(execution_tier, code, sizeof(code)); RunInt32AddTest(execution_tier, code, sizeof(code));
} }
WASM_EXEC_TEST(Int32Add_block2) { WASM_EXEC_TEST(Int32Add_block2) {
EXPERIMENTAL_FLAG_SCOPE(mv); EXPERIMENTAL_FLAG_SCOPE(mv);
static const byte code[] = { static const byte code[] = {
WASM_BLOCK_X(0, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), kExprBr, DEPTH_0), WASM_BLOCK_X(1, WASM_GET_LOCAL(0), WASM_GET_LOCAL(1), kExprBr, DEPTH_0),
kExprI32Add}; kExprI32Add};
RunInt32AddTest(execution_tier, code, sizeof(code)); RunInt32AddTest(execution_tier, code, sizeof(code));
} }
...@@ -138,7 +137,7 @@ WASM_EXEC_TEST(Int32Add_block2) { ...@@ -138,7 +137,7 @@ WASM_EXEC_TEST(Int32Add_block2) {
WASM_EXEC_TEST(Int32Add_multi_if) { WASM_EXEC_TEST(Int32Add_multi_if) {
EXPERIMENTAL_FLAG_SCOPE(mv); EXPERIMENTAL_FLAG_SCOPE(mv);
static const byte code[] = { static const byte code[] = {
WASM_IF_ELSE_X(0, WASM_GET_LOCAL(0), WASM_IF_ELSE_X(1, WASM_GET_LOCAL(0),
WASM_SEQ(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)), WASM_SEQ(WASM_GET_LOCAL(0), WASM_GET_LOCAL(1)),
WASM_SEQ(WASM_GET_LOCAL(1), WASM_GET_LOCAL(0))), WASM_SEQ(WASM_GET_LOCAL(1), WASM_GET_LOCAL(0))),
kExprI32Add}; kExprI32Add};
......
...@@ -137,26 +137,20 @@ uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, const char* name, ...@@ -137,26 +137,20 @@ uint32_t TestingModuleBuilder::AddFunction(FunctionSig* sig, const char* name,
return index; return index;
} }
void TestingModuleBuilder::FreezeSignatureMapAndInitializeWrapperCache() {
if (test_module_->signature_map.is_frozen()) return;
test_module_->signature_map.Freeze();
size_t max_num_sigs = MaxNumExportWrappers(test_module_.get());
Handle<FixedArray> export_wrappers =
isolate_->factory()->NewFixedArray(static_cast<int>(max_num_sigs));
instance_object_->module_object()->set_export_wrappers(*export_wrappers);
}
Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) { Handle<JSFunction> TestingModuleBuilder::WrapCode(uint32_t index) {
FreezeSignatureMapAndInitializeWrapperCache();
SetExecutable(); SetExecutable();
FunctionSig* sig = test_module_->functions[index].sig; return WasmInstanceObject::GetOrCreateWasmExportedFunction(
MaybeHandle<Code> maybe_ret_code = isolate_, instance_object(), index);
compiler::CompileJSToWasmWrapper(isolate_, sig, false);
Handle<Code> ret_code = maybe_ret_code.ToHandleChecked();
Handle<JSFunction> ret = WasmExportedFunction::New(
isolate_, instance_object(), static_cast<int>(index),
static_cast<int>(sig->parameter_count()), ret_code);
// Add reference to the exported wrapper code.
Handle<WasmModuleObject> module_object(instance_object()->module_object(),
isolate_);
Handle<FixedArray> old_arr(module_object->export_wrappers(), isolate_);
Handle<FixedArray> new_arr =
isolate_->factory()->NewFixedArray(old_arr->length() + 1);
old_arr->CopyTo(0, *new_arr, 0, old_arr->length());
new_arr->set(old_arr->length(), *ret_code);
module_object->set_export_wrappers(*new_arr);
return ret;
} }
void TestingModuleBuilder::AddIndirectFunctionTable( void TestingModuleBuilder::AddIndirectFunctionTable(
......
...@@ -179,6 +179,10 @@ class TestingModuleBuilder { ...@@ -179,6 +179,10 @@ class TestingModuleBuilder {
enum FunctionType { kImport, kWasm }; enum FunctionType { kImport, kWasm };
uint32_t AddFunction(FunctionSig* sig, const char* name, FunctionType type); uint32_t AddFunction(FunctionSig* sig, const char* name, FunctionType type);
// Freezes the signature map of the module and allocates the storage for
// export wrappers.
void FreezeSignatureMapAndInitializeWrapperCache();
// Wrap the code so it can be called as a JS function. // Wrap the code so it can be called as a JS function.
Handle<JSFunction> WrapCode(uint32_t index); Handle<JSFunction> WrapCode(uint32_t index);
...@@ -380,6 +384,7 @@ class WasmRunnerBase : public HandleAndZoneScope { ...@@ -380,6 +384,7 @@ class WasmRunnerBase : public HandleAndZoneScope {
const char* name = nullptr) { const char* name = nullptr) {
functions_.emplace_back( functions_.emplace_back(
new WasmFunctionCompiler(&zone_, sig, &builder_, name)); new WasmFunctionCompiler(&zone_, sig, &builder_, name));
builder().AddSignature(sig);
return *functions_.back(); return *functions_.back();
} }
......
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