[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