[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