Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(231)

Unified Diff: src/wasm/wasm-module.cc

Issue 2443353002: [wasm] Add support for exporting WebAssembly.Table instances. (Closed)
Patch Set: Fix identity of exported JSFunctions Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/wasm/wasm-js.cc ('k') | test/mjsunit/wasm/export-table.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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));
+ }
+ }
+ }
}
};
« no previous file with comments | « src/wasm/wasm-js.cc ('k') | test/mjsunit/wasm/export-table.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698