[lld][WebAssembly] Support for growable tables

Adds --growable-table flag to handle building wasm modules with tables
that can grow.

Wasm tables that we use to store function pointers. In order to add functions
to that table at runtime, we need to either preallocate space, or grow the table.
In order to specify a table with no maximum size, we need some flag to handle
that case, separately from a potential --max-table-size= flag.

Note that the number of elements in the table isn't knowable until link-time,
so it's unclear if we will want a --max-table-size= flag in the future.

git-svn-id: https://llvm.org/svn/llvm-project/lld/trunk@370127 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/wasm/growable-table.test b/test/wasm/growable-table.test
new file mode 100644
index 0000000..cd52f2e
--- /dev/null
+++ b/test/wasm/growable-table.test
@@ -0,0 +1,17 @@
+# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+# RUN: wasm-ld --export-table --growable-table -o %t.wasm %t.start.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Verify the --growable-table flag creates a growable table
+
+# CHECK:        - Type:            TABLE
+# CHECK-NEXT:     Tables:
+# CHECK-NEXT:       - ElemType:        FUNCREF
+# CHECK-NEXT:         Limits:
+# CHECK-NEXT:           Initial:         0x00000001
+# CHECK-NEXT:   - Type:
+# CHECK:        - Type:            EXPORT
+# CHECK-NEXT:     Exports:
+# CHECK:            - Name:            __indirect_function_table
+# CHECK-NEXT:         Kind:            TABLE
+# CHECK-NEXT:         Index:           0
diff --git a/wasm/Config.h b/wasm/Config.h
index ab17acf..90a3c40 100644
--- a/wasm/Config.h
+++ b/wasm/Config.h
@@ -31,6 +31,7 @@
   bool exportAll;
   bool exportDynamic;
   bool exportTable;
+  bool growableTable;
   bool gcSections;
   bool importMemory;
   bool sharedMemory;
diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp
index 833a209..499c064 100644
--- a/wasm/Driver.cpp
+++ b/wasm/Driver.cpp
@@ -314,6 +314,7 @@
   config->entry = getEntry(args);
   config->exportAll = args.hasArg(OPT_export_all);
   config->exportTable = args.hasArg(OPT_export_table);
+  config->growableTable = args.hasArg(OPT_growable_table);
   errorHandler().fatalWarnings =
       args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false);
   config->importMemory = args.hasArg(OPT_import_memory);
diff --git a/wasm/Options.td b/wasm/Options.td
index 4bce790..45e3ef9 100644
--- a/wasm/Options.td
+++ b/wasm/Options.td
@@ -134,6 +134,9 @@
 def export_table: F<"export-table">,
   HelpText<"Export function table to the environment">;
 
+def growable_table: F<"growable-table">,
+  HelpText<"Remove maximum size from function table, allowing table to grow">;
+
 def global_base: J<"global-base=">,
   HelpText<"Where to start to place global data">;
 
diff --git a/wasm/SyntheticSections.cpp b/wasm/SyntheticSections.cpp
index 0b0f89b..2cbe56e 100644
--- a/wasm/SyntheticSections.cpp
+++ b/wasm/SyntheticSections.cpp
@@ -216,7 +216,11 @@
 
   raw_ostream &os = bodyOutputStream;
   writeUleb128(os, 1, "table count");
-  WasmLimits limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize};
+  WasmLimits limits;
+  if (config->growableTable)
+    limits = {0, tableSize, 0};
+  else
+    limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize};
   writeTableType(os, WasmTable{WASM_TYPE_FUNCREF, limits});
 }