Index: src/wasm/wasm-module.cc |
diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
index 9d5f4d00ce4713626d25f280219bdbb385f8a824..021a1cbab6d61cfd7af3472da2c8be8c8f29d760 100644 |
--- a/src/wasm/wasm-module.cc |
+++ b/src/wasm/wasm-module.cc |
@@ -1038,6 +1038,8 @@ class WasmInstanceBuilder { |
//-------------------------------------------------------------------------- |
int function_table_count = |
static_cast<int>(module_->function_tables.size()); |
+ std::vector<InitializedTable> inited_tables; |
+ inited_tables.reserve(module_->function_tables.size()); |
if (function_table_count > 0) { |
Handle<FixedArray> old_function_tables = |
compiled_module_->function_tables(); |
@@ -1045,8 +1047,18 @@ class WasmInstanceBuilder { |
factory->NewFixedArray(function_table_count); |
for (int index = 0; index < function_table_count; ++index) { |
WasmIndirectFunctionTable& table = module_->function_tables[index]; |
- uint32_t size = table.max_size > 0 ? table.max_size : table.size; |
- Handle<FixedArray> new_table = factory->NewFixedArray(size * 2); |
+ uint32_t table_size = table.size; |
+ Handle<FixedArray> new_table = factory->NewFixedArray(table_size * 2); |
+ |
+ inited_tables.push_back({Handle<JSObject>::null(), |
+ Handle<FixedArray>::null(), new_table, |
+ std::vector<WasmFunction*>()}); |
+ InitializedTable& init_table = inited_tables.back(); |
+ if (table.exported) { |
+ init_table.new_entries.insert(init_table.new_entries.begin(), |
+ table_size, nullptr); |
+ } |
+ |
for (int i = 0; i < new_table->length(); ++i) { |
static const int kInvalidSigIndex = -1; |
// Fill the table with invalid signature indexes so that uninitialized |
@@ -1055,17 +1067,20 @@ class WasmInstanceBuilder { |
} |
for (auto table_init : module_->table_inits) { |
uint32_t base = EvalUint32InitExpr(globals, table_init.offset); |
- uint32_t table_size = static_cast<uint32_t>(new_table->length()); |
if (base > table_size || |
(base + table_init.entries.size() > table_size)) { |
thrower_->CompileError("table initializer is out of bounds"); |
continue; |
} |
for (size_t i = 0; i < table_init.entries.size(); ++i) { |
- FunctionSig* sig = module_->functions[table_init.entries[i]].sig; |
+ WasmFunction* func = &module_->functions[table_init.entries[i]]; |
+ if (table.exported) { |
+ init_table.new_entries[i + base] = func; |
+ } |
+ FunctionSig* sig = func->sig; |
int32_t sig_index = table.map.Find(sig); |
new_table->set(static_cast<int>(i + base), Smi::FromInt(sig_index)); |
- new_table->set(static_cast<int>(i + base + size), |
+ new_table->set(static_cast<int>(i + base + table_size), |
code_table->get(table_init.entries[i])); |
} |
} |
@@ -1087,7 +1102,7 @@ class WasmInstanceBuilder { |
//-------------------------------------------------------------------------- |
// Set up the exports object for the new instance. |
//-------------------------------------------------------------------------- |
- ProcessExports(globals, code_table, instance); |
+ ProcessExports(globals, inited_tables, code_table, instance); |
if (num_imported_functions > 0 || !owner.is_null()) { |
// If the code was cloned, or new imports were compiled, patch. |
@@ -1175,6 +1190,14 @@ class WasmInstanceBuilder { |
} |
private: |
+ // Represents the initialized state of a table. |
+ struct InitializedTable { |
+ Handle<JSObject> table_object; // WebAssembly.Table instance |
+ Handle<FixedArray> js_functions; // JSFunctions exported |
+ Handle<FixedArray> dispatch_table; // internal (code, sig) pairs |
+ std::vector<WasmFunction*> new_entries; // overwriting entries |
+ }; |
+ |
Isolate* isolate_; |
WasmModule* module_; |
ErrorThrower* thrower_; |
@@ -1496,10 +1519,27 @@ class WasmInstanceBuilder { |
// Process the exports, creating wrappers for functions, tables, memories, |
// and globals. |
void ProcessExports(MaybeHandle<JSArrayBuffer> globals, |
+ std::vector<InitializedTable>& inited_tables, |
Handle<FixedArray> code_table, |
Handle<JSObject> instance) { |
if (module_->export_table.size() == 0) return; |
+ // Allocate a table to cache the exported JSFunctions if needed. |
+ bool has_exported_functions = module_->num_exported_functions > 0; |
+ if (!has_exported_functions) { |
+ for (auto table : module_->function_tables) { |
+ if (table.exported) { |
+ has_exported_functions = true; |
+ break; |
+ } |
+ } |
+ } |
+ Handle<FixedArray> exported_functions = |
+ has_exported_functions |
+ ? isolate_->factory()->NewFixedArray( |
+ static_cast<int>(module_->functions.size())) |
+ : Handle<FixedArray>::null(); |
+ |
Handle<JSObject> exports_object = instance; |
if (module_->origin == kWasmOrigin) { |
// Create the "exports" object. |
@@ -1527,17 +1567,36 @@ class WasmInstanceBuilder { |
WasmFunction& function = module_->functions[exp.index]; |
int export_index = |
static_cast<int>(module_->functions.size() + func_index); |
- Handle<Code> export_code = |
- code_table->GetValueChecked<Code>(isolate_, export_index); |
- desc.set_value(WrapExportCodeAsJSFunction( |
- isolate_, export_code, name, function.sig, func_index, instance)); |
+ Handle<Object> value(exported_functions->get(exp.index), isolate_); |
+ Handle<JSFunction> js_function; |
+ if (value->IsJSFunction()) { |
+ // There already is a JSFunction for this WASM function. |
+ js_function = Handle<JSFunction>::cast(value); |
+ } else { |
+ // Wrap the exported code as a JSFunction. |
+ Handle<Code> export_code = |
+ code_table->GetValueChecked<Code>(isolate_, export_index); |
+ js_function = |
+ WrapExportCodeAsJSFunction(isolate_, export_code, name, |
+ function.sig, func_index, instance); |
+ exported_functions->set(exp.index, *js_function); |
+ } |
+ desc.set_value(js_function); |
func_index++; |
break; |
} |
- case kExternalTable: |
- // TODO(titzer): create a WebAssembly.Table instance. |
- // TODO(titzer): should it have the same identity as an import? |
+ case kExternalTable: { |
+ InitializedTable& init_table = inited_tables[exp.index]; |
+ WasmIndirectFunctionTable& table = |
+ module_->function_tables[exp.index]; |
+ if (init_table.table_object.is_null()) { |
+ init_table.table_object = WasmJs::CreateWasmTableObject( |
+ isolate_, table.size, table.max_size != 0, table.max_size, |
+ &init_table.js_functions); |
+ } |
+ desc.set_value(init_table.table_object); |
break; |
+ } |
case kExternalMemory: { |
// Export the memory as a WebAssembly.Memory object. |
Handle<Object> memory_object( |
@@ -1589,6 +1648,47 @@ class WasmInstanceBuilder { |
return; |
} |
} |
+ |
+ // Fill out the contents of WebAssembly.Table instances. |
+ if (!exported_functions.is_null()) { |
+ // TODO(titzer): We compile JS->WASM wrappers for any function that is a |
+ // member of an exported indirect table that is not itself exported. This |
+ // should be done at compile time and cached instead. |
+ WasmInstance temp_instance(module_); |
+ temp_instance.context = isolate_->native_context(); |
+ temp_instance.mem_size = 0; |
+ temp_instance.mem_start = nullptr; |
+ temp_instance.globals_start = nullptr; |
+ |
+ ModuleEnv module_env; |
+ module_env.module = module_; |
+ module_env.instance = &temp_instance; |
+ module_env.origin = module_->origin; |
+ |
+ // Fill the exported tables with JSFunctions. |
+ for (auto inited_table : inited_tables) { |
+ if (inited_table.js_functions.is_null()) continue; |
+ for (int i = 0; i < static_cast<int>(inited_table.new_entries.size()); |
+ i++) { |
+ if (inited_table.new_entries[i] == nullptr) continue; |
+ int func_index = |
+ static_cast<int>(inited_table.new_entries[i]->func_index); |
+ if (!exported_functions->get(func_index)->IsJSFunction()) { |
+ // No JSFunction entry yet exists for this function. Create one. |
+ Handle<Code> wasm_code(Code::cast(code_table->get(func_index)), |
+ isolate_); |
+ Handle<Code> wrapper_code = compiler::CompileJSToWasmWrapper( |
+ isolate_, &module_env, wasm_code, func_index); |
+ Handle<JSFunction> js_function = WrapExportCodeAsJSFunction( |
+ isolate_, wrapper_code, isolate_->factory()->empty_string(), |
+ module_->functions[func_index].sig, func_index, instance); |
+ exported_functions->set(func_index, *js_function); |
+ } |
+ inited_table.js_functions->set(i, |
+ exported_functions->get(func_index)); |
+ } |
+ } |
+ } |
} |
}; |