[wasm] Support importing anyref tables
R=clemensh@chromium.org
Bug: v8:7581
Change-Id: I6b20698e556ed3808f8b190f88cb700301825b54
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1588432
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: Clemens Hammacher <clemensh@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61129}
diff --git a/src/wasm/module-instantiate.cc b/src/wasm/module-instantiate.cc
index bbeabc8..9706d24 100644
--- a/src/wasm/module-instantiate.cc
+++ b/src/wasm/module-instantiate.cc
@@ -140,6 +140,11 @@
Handle<String> import_name,
Handle<Object> value);
+ // Initialize imported tables of type anyfunc.
+ bool InitializeImportedIndirectFunctionTable(
+ Handle<WasmInstanceObject> instance, int import_index,
+ Handle<WasmTableObject> table_object);
+
// Process a single imported table.
bool ProcessImportedTable(Handle<WasmInstanceObject> instance,
int import_index, int table_index,
@@ -808,6 +813,49 @@
return true;
}
+bool InstanceBuilder::InitializeImportedIndirectFunctionTable(
+ Handle<WasmInstanceObject> instance, int import_index,
+ Handle<WasmTableObject> table_object) {
+ int imported_table_size = table_object->elements().length();
+ // Allocate a new dispatch table.
+ if (!instance->has_indirect_function_table()) {
+ WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
+ instance, imported_table_size);
+ }
+ // Initialize the dispatch table with the (foreign) JS functions
+ // that are already in the table.
+ for (int i = 0; i < imported_table_size; ++i) {
+ bool is_valid;
+ bool is_null;
+ MaybeHandle<WasmInstanceObject> maybe_target_instance;
+ int function_index;
+ WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
+ &is_null, &maybe_target_instance,
+ &function_index);
+ if (!is_valid) {
+ thrower_->LinkError("table import %d[%d] is not a wasm function",
+ import_index, i);
+ return false;
+ }
+ if (is_null) continue;
+
+ Handle<WasmInstanceObject> target_instance =
+ maybe_target_instance.ToHandleChecked();
+ FunctionSig* sig = target_instance->module_object()
+ ->module()
+ ->functions[function_index]
+ .sig;
+
+ // Look up the signature's canonical id. If there is no canonical
+ // id, then the signature does not appear at all in this module,
+ // so putting {-1} in the table will cause checks to always fail.
+ IndirectFunctionTableEntry(instance, i)
+ .Set(module_->signature_map.Find(*sig), target_instance,
+ function_index);
+ }
+ return true;
+}
+
bool InstanceBuilder::ProcessImportedTable(Handle<WasmInstanceObject> instance,
int import_index, int table_index,
Handle<String> module_name,
@@ -851,42 +899,17 @@
}
}
- // Allocate a new dispatch table.
- if (!instance->has_indirect_function_table()) {
- WasmInstanceObject::EnsureIndirectFunctionTableWithMinimumSize(
- instance, imported_table_size);
+ if (table.type != table_object->type()) {
+ ReportLinkError("imported table does not match the expected type",
+ import_index, module_name, import_name);
+ return false;
}
- // Initialize the dispatch table with the (foreign) JS functions
- // that are already in the table.
- for (int i = 0; i < imported_table_size; ++i) {
- bool is_valid;
- bool is_null;
- MaybeHandle<WasmInstanceObject> maybe_target_instance;
- int function_index;
- WasmTableObject::GetFunctionTableEntry(isolate_, table_object, i, &is_valid,
- &is_null, &maybe_target_instance,
- &function_index);
- if (!is_valid) {
- thrower_->LinkError("table import %d[%d] is not a wasm function",
- import_index, i);
- return false;
- }
- if (is_null) continue;
- Handle<WasmInstanceObject> target_instance =
- maybe_target_instance.ToHandleChecked();
- FunctionSig* sig = target_instance->module_object()
- ->module()
- ->functions[function_index]
- .sig;
-
- // Look up the signature's canonical id. If there is no canonical
- // id, then the signature does not appear at all in this module,
- // so putting {-1} in the table will cause checks to always fail.
- IndirectFunctionTableEntry(instance, i)
- .Set(module_->signature_map.Find(*sig), target_instance,
- function_index);
+ if (table.type == kWasmAnyFunc && !InitializeImportedIndirectFunctionTable(
+ instance, import_index, table_object)) {
+ return false;
}
+
return true;
}
diff --git a/test/mjsunit/wasm/anyref-table.js b/test/mjsunit/wasm/anyref-table.js
index f924819..f4e82d3 100644
--- a/test/mjsunit/wasm/anyref-table.js
+++ b/test/mjsunit/wasm/anyref-table.js
@@ -29,3 +29,19 @@
assertThrows(() => table.set(12), RangeError);
})();
+
+(function TestImportAnyRefTable() {
+ print(arguments.callee.name);
+
+ const builder = new WasmModuleBuilder();
+ const table_index = builder.addImportedTable("imp", "table", 3, 10, kWasmAnyRef);
+ builder.addFunction('get', kSig_r_v)
+ .addBody([kExprI32Const, 0, kExprGetTable, table_index]);
+
+ let table_ref = new WebAssembly.Table({element: "anyref", initial: 3, maximum: 10});
+ builder.instantiate({imp:{table: table_ref}});
+
+ let table_func = new WebAssembly.Table({ element: "anyfunc", initial: 3, maximum: 10 });
+ assertThrows(() => builder.instantiate({ imp: { table: table_func } }),
+ WebAssembly.LinkError, /imported table does not match the expected type/);
+})();
diff --git a/test/mjsunit/wasm/wasm-module-builder.js b/test/mjsunit/wasm/wasm-module-builder.js
index 7f63ea8..bb1bcf4 100644
--- a/test/mjsunit/wasm/wasm-module-builder.js
+++ b/test/mjsunit/wasm/wasm-module-builder.js
@@ -843,12 +843,12 @@
return this;
}
- addImportedTable(module, name, initial, maximum) {
+ addImportedTable(module, name, initial, maximum, type) {
if (this.tables.length != 0) {
throw new Error('Imported tables must be declared before local ones');
}
let o = {module: module, name: name, kind: kExternalTable, initial: initial,
- maximum: maximum};
+ maximum: maximum, type: type || kWasmAnyFunctionTypeForm};
this.imports.push(o);
return this.num_imported_tables++;
}
@@ -999,7 +999,7 @@
section.emit_u32v(imp.initial); // initial
if (has_max) section.emit_u32v(imp.maximum); // maximum
} else if (imp.kind == kExternalTable) {
- section.emit_u8(kWasmAnyFunctionTypeForm);
+ section.emit_u8(imp.type);
var has_max = (typeof imp.maximum) != "undefined";
section.emit_u8(has_max ? 1 : 0); // flags
section.emit_u32v(imp.initial); // initial