[lld] r328643 - [WebAssembly] Add export/import for function pointer table

Nicholas Wilson via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 27 10:38:51 PDT 2018


Author: ncw
Date: Tue Mar 27 10:38:51 2018
New Revision: 328643

URL: http://llvm.org/viewvc/llvm-project?rev=328643&view=rev
Log:
[WebAssembly] Add export/import for function pointer table

This enables callback-style programming where the JavaScript environment
can call back into the Wasm environment using a function pointer
received from the module.

Differential Revision: https://reviews.llvm.org/D44427

Added:
    lld/trunk/test/wasm/export-table.test
    lld/trunk/test/wasm/import-table.test
Modified:
    lld/trunk/wasm/Config.h
    lld/trunk/wasm/Driver.cpp
    lld/trunk/wasm/Options.td
    lld/trunk/wasm/Writer.cpp
    lld/trunk/wasm/WriterUtils.cpp
    lld/trunk/wasm/WriterUtils.h

Added: lld/trunk/test/wasm/export-table.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/export-table.test?rev=328643&view=auto
==============================================================================
--- lld/trunk/test/wasm/export-table.test (added)
+++ lld/trunk/test/wasm/export-table.test Tue Mar 27 10:38:51 2018
@@ -0,0 +1,19 @@
+# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+# RUN: wasm-ld --check-signatures --export-table -o %t.wasm %t.start.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Verify the --export-table flag creates a table export
+
+# CHECK:        - Type:            TABLE
+# CHECK-NEXT:     Tables:
+# CHECK-NEXT:       - ElemType:        ANYFUNC
+# CHECK-NEXT:         Limits:
+# CHECK-NEXT:           Flags:           [ HAS_MAX ]
+# CHECK-NEXT:           Initial:         0x00000001
+# CHECK-NEXT:           Maximum:         0x00000001
+# CHECK-NEXT:   - Type:
+# CHECK:        - Type:            EXPORT
+# CHECK-NEXT:     Exports:
+# CHECK:            - Name:            __indirect_function_table
+# CHECK-NEXT:         Kind:            TABLE
+# CHECK-NEXT:         Index:           0

Added: lld/trunk/test/wasm/import-table.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/wasm/import-table.test?rev=328643&view=auto
==============================================================================
--- lld/trunk/test/wasm/import-table.test (added)
+++ lld/trunk/test/wasm/import-table.test Tue Mar 27 10:38:51 2018
@@ -0,0 +1,18 @@
+# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o
+# RUN: wasm-ld --check-signatures --import-table -o %t.wasm %t.start.o
+# RUN: obj2yaml %t.wasm | FileCheck %s
+
+# Verify the --import-table flag creates a table import
+
+# CHECK:       - Type:            IMPORT
+# CHECK-NEXT:    Imports:
+# CHECK-NEXT:      - Module:          env
+# CHECK-NEXT:        Field:           __indirect_function_table
+# CHECK-NEXT:        Kind:            TABLE
+# CHECK-NEXT:        Table:
+# CHECK-NEXT:          ElemType:        ANYFUNC
+# CHECK-NEXT:          Limits:
+# CHECK-NEXT:            Flags:           [ HAS_MAX ]
+# CHECK-NEXT:            Initial:         0x00000001
+# CHECK-NEXT:            Maximum:         0x00000001
+

Modified: lld/trunk/wasm/Config.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Config.h?rev=328643&r1=328642&r2=328643&view=diff
==============================================================================
--- lld/trunk/wasm/Config.h (original)
+++ lld/trunk/wasm/Config.h Tue Mar 27 10:38:51 2018
@@ -17,6 +17,8 @@
 namespace lld {
 namespace wasm {
 
+enum class ExposeAs { IMPORT, EXPORT, NONE };
+
 struct Configuration {
   bool AllowUndefined;
   bool CheckSignatures;
@@ -27,6 +29,7 @@ struct Configuration {
   bool Relocatable;
   bool StripAll;
   bool StripDebug;
+  ExposeAs Table;
   uint32_t GlobalBase;
   uint32_t InitialMemory;
   uint32_t MaxMemory;

Modified: lld/trunk/wasm/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Driver.cpp?rev=328643&r1=328642&r2=328643&view=diff
==============================================================================
--- lld/trunk/wasm/Driver.cpp (original)
+++ lld/trunk/wasm/Driver.cpp Tue Mar 27 10:38:51 2018
@@ -216,6 +216,15 @@ static StringRef getEntry(opt::InputArgL
   return Arg->getValue();
 }
 
+static ExposeAs getExpose(opt::InputArgList &Args, unsigned Import,
+                          unsigned Export) {
+  auto *Arg = Args.getLastArg(Import, Export);
+  if (!Arg)
+    return ExposeAs::NONE;
+  return Arg->getOption().getID() == Import ? ExposeAs::IMPORT
+                                            : ExposeAs::EXPORT;
+}
+
 static const uint8_t UnreachableFn[] = {
     0x03 /* ULEB length */, 0x00 /* ULEB num locals */,
     0x00 /* opcode unreachable */, 0x0b /* opcode end */
@@ -296,6 +305,7 @@ void LinkerDriver::link(ArrayRef<const c
   Config->SearchPaths = args::getStrings(Args, OPT_L);
   Config->StripAll = Args.hasArg(OPT_strip_all);
   Config->StripDebug = Args.hasArg(OPT_strip_debug);
+  Config->Table = getExpose(Args, OPT_import_table, OPT_export_table);
   errorHandler().Verbose = Args.hasArg(OPT_verbose);
   ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true);
 

Modified: lld/trunk/wasm/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Options.td?rev=328643&r1=328642&r2=328643&view=diff
==============================================================================
--- lld/trunk/wasm/Options.td (original)
+++ lld/trunk/wasm/Options.td Tue Mar 27 10:38:51 2018
@@ -103,12 +103,18 @@ defm check_signatures: B<"check-signatur
 defm export: Eq<"export">,
   HelpText<"Force a symbol to be exported">;
 
+def export_table: F<"export-table">,
+  HelpText<"Export function table to the environment">;
+
 def global_base: J<"global-base=">,
   HelpText<"Where to start to place global data">;
 
 def import_memory: F<"import-memory">,
   HelpText<"Import memory from the environment">;
 
+def import_table: F<"import-table">,
+  HelpText<"Import function table from the environment">;
+
 def initial_memory: J<"initial-memory=">,
   HelpText<"Initial size of the linear memory">;
 

Modified: lld/trunk/wasm/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/Writer.cpp?rev=328643&r1=328642&r2=328643&view=diff
==============================================================================
--- lld/trunk/wasm/Writer.cpp (original)
+++ lld/trunk/wasm/Writer.cpp Tue Mar 27 10:38:51 2018
@@ -39,6 +39,7 @@ using namespace lld::wasm;
 
 static constexpr int kStackAlignment = 16;
 static constexpr int kInitialTableOffset = 1;
+static constexpr const char *kFunctionTableName = "__indirect_function_table";
 
 namespace {
 
@@ -126,6 +127,8 @@ void Writer::createImportSection() {
   uint32_t NumImports = ImportedSymbols.size();
   if (Config->ImportMemory)
     ++NumImports;
+  if (Config->Table == ExposeAs::IMPORT)
+    ++NumImports;
 
   if (NumImports == 0)
     return;
@@ -149,6 +152,17 @@ void Writer::createImportSection() {
     writeImport(OS, Import);
   }
 
+  if (Config->Table == ExposeAs::IMPORT) {
+    uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size();
+    WasmImport Import;
+    Import.Module = "env";
+    Import.Field = kFunctionTableName;
+    Import.Kind = WASM_EXTERNAL_TABLE;
+    Import.Table.ElemType = WASM_TYPE_ANYFUNC;
+    Import.Table.Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
+    writeImport(OS, Import);
+  }
+
   for (const Symbol *Sym : ImportedSymbols) {
     WasmImport Import;
     Import.Module = "env";
@@ -222,8 +236,11 @@ void Writer::createGlobalSection() {
 }
 
 void Writer::createTableSection() {
-  // Always output a table section, even if there are no indirect calls.
-  // There are two reasons for this:
+  if (Config->Table == ExposeAs::IMPORT)
+    return;
+
+  // Always output a table section (or table import), even if there are no
+  // indirect calls.  There are two reasons for this:
   //  1. For executables it is useful to have an empty table slot at 0
   //     which can be filled with a null function call handler.
   //  2. If we don't do this, any program that contains a call_indirect but
@@ -236,16 +253,16 @@ void Writer::createTableSection() {
   raw_ostream &OS = Section->getStream();
 
   writeUleb128(OS, 1, "table count");
-  writeU8(OS, WASM_TYPE_ANYFUNC, "table type");
-  writeUleb128(OS, WASM_LIMITS_FLAG_HAS_MAX, "table flags");
-  writeUleb128(OS, TableSize, "table initial size");
-  writeUleb128(OS, TableSize, "table max size");
+  WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize};
+  writeTableType(OS, WasmTable{WASM_TYPE_ANYFUNC, Limits});
 }
 
 void Writer::createExportSection() {
   bool ExportMemory = !Config->Relocatable && !Config->ImportMemory;
+  bool ExportTable = !Config->Relocatable && Config->Table == ExposeAs::EXPORT;
 
-  uint32_t NumExports = (ExportMemory ? 1 : 0) + ExportedSymbols.size();
+  uint32_t NumExports =
+      (ExportMemory ? 1 : 0) + (ExportTable ? 1 : 0) + ExportedSymbols.size();
   if (!NumExports)
     return;
 
@@ -256,6 +273,8 @@ void Writer::createExportSection() {
 
   if (ExportMemory)
     writeExport(OS, {"memory", WASM_EXTERNAL_MEMORY, 0});
+  if (ExportTable)
+    writeExport(OS, {kFunctionTableName, WASM_EXTERNAL_TABLE, 0});
 
   unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size();
 

Modified: lld/trunk/wasm/WriterUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/WriterUtils.cpp?rev=328643&r1=328642&r2=328643&view=diff
==============================================================================
--- lld/trunk/wasm/WriterUtils.cpp (original)
+++ lld/trunk/wasm/WriterUtils.cpp Tue Mar 27 10:38:51 2018
@@ -126,6 +126,11 @@ void wasm::writeGlobal(raw_ostream &OS,
   writeInitExpr(OS, Global.InitExpr);
 }
 
+void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) {
+  writeU8(OS, WASM_TYPE_ANYFUNC, "table type");
+  writeLimits(OS, Type.Limits);
+}
+
 void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) {
   writeStr(OS, Import.Module, "import module name");
   writeStr(OS, Import.Field, "import field name");
@@ -140,6 +145,9 @@ void wasm::writeImport(raw_ostream &OS,
   case WASM_EXTERNAL_MEMORY:
     writeLimits(OS, Import.Memory);
     break;
+  case WASM_EXTERNAL_TABLE:
+    writeTableType(OS, Import.Table);
+    break;
   default:
     fatal("unsupported import type: " + Twine(Import.Kind));
   }
@@ -158,6 +166,9 @@ void wasm::writeExport(raw_ostream &OS,
   case WASM_EXTERNAL_MEMORY:
     writeUleb128(OS, Export.Index, "memory index");
     break;
+  case WASM_EXTERNAL_TABLE:
+    writeUleb128(OS, Export.Index, "table index");
+    break;
   default:
     fatal("unsupported export type: " + Twine(Export.Kind));
   }

Modified: lld/trunk/wasm/WriterUtils.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/wasm/WriterUtils.h?rev=328643&r1=328642&r2=328643&view=diff
==============================================================================
--- lld/trunk/wasm/WriterUtils.h (original)
+++ lld/trunk/wasm/WriterUtils.h Tue Mar 27 10:38:51 2018
@@ -47,6 +47,8 @@ void writeGlobalType(raw_ostream &OS, co
 
 void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global);
 
+void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type);
+
 void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import);
 
 void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export);




More information about the llvm-commits mailing list