Chromium Code Reviews| Index: src/wasm/wasm-module.cc |
| diff --git a/src/wasm/wasm-module.cc b/src/wasm/wasm-module.cc |
| index 9d5f4d00ce4713626d25f280219bdbb385f8a824..d7f2655f7941ed4bb110100865bd22aaa18c65ec 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(), |
|
bradnelson
2016/10/25 07:33:39
There will be one by default correct?
titzer
2016/10/25 08:27:37
This code handles any number of tables with any si
|
| + 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,22 @@ 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; |
| + // If there are any exported tables, cache the JSFunctions created |
|
rossberg
2016/10/25 08:19:20
Don't you need to do that anyway, in case the same
titzer
2016/10/25 08:23:13
I don't think we've spec'd that case yet.
As it is
rossberg
2016/10/25 08:28:59
Actually, JS.md explicitly requires it. ;)
|
| + // for export to reuse in the exported tables. |
| + Handle<FixedArray> exported_functions; |
| + for (auto table : module_->function_tables) { |
| + if (table.exported) { |
| + exported_functions = isolate_->factory()->NewFixedArray( |
| + static_cast<int>(module_->functions.size())); |
| + break; |
| + } |
| + } |
| + |
| Handle<JSObject> exports_object = instance; |
| if (module_->origin == kWasmOrigin) { |
| // Create the "exports" object. |
| @@ -1529,15 +1564,27 @@ class WasmInstanceBuilder { |
| static_cast<int>(module_->functions.size() + func_index); |
| Handle<Code> export_code = |
|
rossberg
2016/10/25 08:19:20
Like here, you should first check whether exported
titzer
2016/10/25 08:23:13
That would mean that there would be only one expor
|
| code_table->GetValueChecked<Code>(isolate_, export_index); |
| - desc.set_value(WrapExportCodeAsJSFunction( |
| - isolate_, export_code, name, function.sig, func_index, instance)); |
| + Handle<JSFunction> js_function = WrapExportCodeAsJSFunction( |
| + isolate_, export_code, name, function.sig, func_index, instance); |
| + if (!exported_functions.is_null()) { |
| + 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 +1636,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 |
| + // could 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); |
|
bradnelson
2016/10/25 07:33:39
These can only be in bounds correct? DCHECK?
titzer
2016/10/25 08:27:37
The loop iterates over the inited_table.new_entrie
|
| + 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)); |
| + } |
| + } |
| + } |
| } |
| }; |