diff --git a/lld/test/wasm/alias.s b/lld/test/wasm/alias.s --- a/lld/test/wasm/alias.s +++ b/lld/test/wasm/alias.s @@ -24,7 +24,8 @@ # CHECK-NEXT: FunctionTypes: [ 0 ] # CHECK-NEXT: - Type: TABLE # CHECK-NEXT: Tables: -# CHECK-NEXT: - ElemType: FUNCREF +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: ElemType: FUNCREF # CHECK-NEXT: Limits: # CHECK-NEXT: Flags: [ HAS_MAX ] # CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/test/wasm/call-indirect.ll b/lld/test/wasm/call-indirect.ll --- a/lld/test/wasm/call-indirect.ll +++ b/lld/test/wasm/call-indirect.ll @@ -63,7 +63,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0, 3, 1, 3, 4 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000003 diff --git a/lld/test/wasm/export-table.test b/lld/test/wasm/export-table.test --- a/lld/test/wasm/export-table.test +++ b/lld/test/wasm/export-table.test @@ -6,7 +6,8 @@ # CHECK: - Type: TABLE # CHECK-NEXT: Tables: -# CHECK-NEXT: - ElemType: FUNCREF +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: ElemType: FUNCREF # CHECK-NEXT: Limits: # CHECK-NEXT: Flags: [ HAS_MAX ] # CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/test/wasm/growable-table.test b/lld/test/wasm/growable-table.test --- a/lld/test/wasm/growable-table.test +++ b/lld/test/wasm/growable-table.test @@ -6,7 +6,8 @@ # CHECK: - Type: TABLE # CHECK-NEXT: Tables: -# CHECK-NEXT: - ElemType: FUNCREF +# CHECK-NEXT: - Index: 0 +# CHECK-NEXT: ElemType: FUNCREF # CHECK-NEXT: Limits: # CHECK-NEXT: Initial: 0x00000001 # CHECK-NEXT: - Type: diff --git a/lld/test/wasm/import-table.test b/lld/test/wasm/import-table.test --- a/lld/test/wasm/import-table.test +++ b/lld/test/wasm/import-table.test @@ -10,6 +10,7 @@ # CHECK-NEXT: Field: __indirect_function_table # CHECK-NEXT: Kind: TABLE # CHECK-NEXT: Table: +# CHECK-NEXT: Index: 0 # CHECK-NEXT: ElemType: FUNCREF # CHECK-NEXT: Limits: # CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/test/wasm/local-symbols.ll b/lld/test/wasm/local-symbols.ll --- a/lld/test/wasm/local-symbols.ll +++ b/lld/test/wasm/local-symbols.ll @@ -37,7 +37,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/test/wasm/locals-duplicate.test b/lld/test/wasm/locals-duplicate.test --- a/lld/test/wasm/locals-duplicate.test +++ b/lld/test/wasm/locals-duplicate.test @@ -18,7 +18,8 @@ ; CHECK-NEXT: 0, 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000007 @@ -229,7 +230,8 @@ ; RELOC-NEXT: 0, 0 ] ; RELOC-NEXT: - Type: TABLE ; RELOC-NEXT: Tables: -; RELOC-NEXT: - ElemType: FUNCREF +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: ElemType: FUNCREF ; RELOC-NEXT: Limits: ; RELOC-NEXT: Flags: [ HAS_MAX ] ; RELOC-NEXT: Initial: 0x00000007 diff --git a/lld/test/wasm/pie.ll b/lld/test/wasm/pie.ll --- a/lld/test/wasm/pie.ll +++ b/lld/test/wasm/pie.ll @@ -36,6 +36,7 @@ ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/test/wasm/relocatable.ll b/lld/test/wasm/relocatable.ll --- a/lld/test/wasm/relocatable.ll +++ b/lld/test/wasm/relocatable.ll @@ -67,7 +67,8 @@ ; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000004 diff --git a/lld/test/wasm/shared-memory-no-atomics.yaml b/lld/test/wasm/shared-memory-no-atomics.yaml --- a/lld/test/wasm/shared-memory-no-atomics.yaml +++ b/lld/test/wasm/shared-memory-no-atomics.yaml @@ -19,6 +19,7 @@ Field: __indirect_function_table Kind: TABLE Table: + Index: 0 ElemType: FUNCREF Limits: Initial: 0x00000000 diff --git a/lld/test/wasm/shared-memory.yaml b/lld/test/wasm/shared-memory.yaml --- a/lld/test/wasm/shared-memory.yaml +++ b/lld/test/wasm/shared-memory.yaml @@ -27,6 +27,7 @@ Field: __indirect_function_table Kind: TABLE Table: + Index: 0 ElemType: FUNCREF Limits: Initial: 0x00000000 diff --git a/lld/test/wasm/shared.ll b/lld/test/wasm/shared.ll --- a/lld/test/wasm/shared.ll +++ b/lld/test/wasm/shared.ll @@ -72,6 +72,7 @@ ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000002 diff --git a/lld/test/wasm/stack-pointer.ll b/lld/test/wasm/stack-pointer.ll --- a/lld/test/wasm/stack-pointer.ll +++ b/lld/test/wasm/stack-pointer.ll @@ -32,7 +32,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/test/wasm/undefined-weak-call.ll b/lld/test/wasm/undefined-weak-call.ll --- a/lld/test/wasm/undefined-weak-call.ll +++ b/lld/test/wasm/undefined-weak-call.ll @@ -46,7 +46,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 2 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/test/wasm/weak-alias-overide.ll b/lld/test/wasm/weak-alias-overide.ll --- a/lld/test/wasm/weak-alias-overide.ll +++ b/lld/test/wasm/weak-alias-overide.ll @@ -36,7 +36,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000003 diff --git a/lld/test/wasm/weak-alias.ll b/lld/test/wasm/weak-alias.ll --- a/lld/test/wasm/weak-alias.ll +++ b/lld/test/wasm/weak-alias.ll @@ -33,7 +33,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000002 @@ -149,7 +150,8 @@ ; RELOC-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ] ; RELOC-NEXT: - Type: TABLE ; RELOC-NEXT: Tables: -; RELOC-NEXT: - ElemType: FUNCREF +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: ElemType: FUNCREF ; RELOC-NEXT: Limits: ; RELOC-NEXT: Flags: [ HAS_MAX ] ; RELOC-NEXT: Initial: 0x00000002 diff --git a/lld/test/wasm/weak-symbols.ll b/lld/test/wasm/weak-symbols.ll --- a/lld/test/wasm/weak-symbols.ll +++ b/lld/test/wasm/weak-symbols.ll @@ -33,7 +33,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000002 diff --git a/lld/test/wasm/weak-undefined.ll b/lld/test/wasm/weak-undefined.ll --- a/lld/test/wasm/weak-undefined.ll +++ b/lld/test/wasm/weak-undefined.ll @@ -44,7 +44,8 @@ ; CHECK-NEXT: FunctionTypes: [ 0, 0, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: -; CHECK-NEXT: - ElemType: FUNCREF +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] ; CHECK-NEXT: Initial: 0x00000001 diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -223,7 +223,7 @@ limits = {0, tableSize, 0}; else limits = {WASM_LIMITS_FLAG_HAS_MAX, tableSize, tableSize}; - writeTableType(os, WasmTable{WASM_TYPE_FUNCREF, limits}); + writeTableType(os, WasmTable{0, WASM_TYPE_FUNCREF, limits}); } void MemorySection::writeBody() { diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -32,6 +32,8 @@ return "v128"; case ValType::EXNREF: return "exnref"; + case ValType::FUNCREF: + return "funcref"; case ValType::EXTERNREF: return "externref"; } diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -41,7 +41,7 @@ uint32_t MemoryAlignment; // P2 alignment of memory uint32_t TableSize; // Table size in elements uint32_t TableAlignment; // P2 alignment of table - std::vector Needed; // Shared library depenedencies + std::vector Needed; // Shared library dependencies }; struct WasmProducerInfo { @@ -68,6 +68,7 @@ }; struct WasmTable { + uint32_t Index; uint8_t ElemType; WasmLimits Limits; }; @@ -325,6 +326,7 @@ WASM_SYMBOL_TYPE_GLOBAL = 0x2, WASM_SYMBOL_TYPE_SECTION = 0x3, WASM_SYMBOL_TYPE_EVENT = 0x4, + WASM_SYMBOL_TYPE_TABLE = 0x5, }; // Kinds of event attributes. @@ -361,6 +363,7 @@ F64 = WASM_TYPE_F64, V128 = WASM_TYPE_V128, EXNREF = WASM_TYPE_EXNREF, + FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, }; diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -25,6 +25,7 @@ Optional ExportName; wasm::WasmSignature *Signature = nullptr; Optional GlobalType; + Optional TableType; Optional EventType; /// An expression describing how to calculate the size of a symbol. If a @@ -42,6 +43,7 @@ bool isFunction() const { return Type == wasm::WASM_SYMBOL_TYPE_FUNCTION; } bool isData() const { return Type == wasm::WASM_SYMBOL_TYPE_DATA; } bool isGlobal() const { return Type == wasm::WASM_SYMBOL_TYPE_GLOBAL; } + bool isTable() const { return Type == wasm::WASM_SYMBOL_TYPE_TABLE; } bool isSection() const { return Type == wasm::WASM_SYMBOL_TYPE_SECTION; } bool isEvent() const { return Type == wasm::WASM_SYMBOL_TYPE_EVENT; } wasm::WasmSymbolType getType() const { return Type; } @@ -109,6 +111,12 @@ } void setGlobalType(wasm::WasmGlobalType GT) { GlobalType = GT; } + const wasm::ValType &getTableType() const { + assert(TableType.hasValue()); + return TableType.getValue(); + } + void setTableType(wasm::ValType TT) { TableType = TT; } + const wasm::WasmEventType &getEventType() const { assert(EventType.hasValue()); return EventType.getValue(); diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -35,14 +35,15 @@ class WasmSymbol { public: WasmSymbol(const wasm::WasmSymbolInfo &Info, - const wasm::WasmGlobalType *GlobalType, + const wasm::WasmGlobalType *GlobalType, const uint8_t TableType, const wasm::WasmEventType *EventType, const wasm::WasmSignature *Signature) - : Info(Info), GlobalType(GlobalType), EventType(EventType), - Signature(Signature) {} + : Info(Info), GlobalType(GlobalType), TableType(TableType), + EventType(EventType), Signature(Signature) {} const wasm::WasmSymbolInfo &Info; const wasm::WasmGlobalType *GlobalType; + const uint8_t TableType; const wasm::WasmEventType *EventType; const wasm::WasmSignature *Signature; @@ -149,6 +150,7 @@ ArrayRef debugNames() const { return DebugNames; } uint32_t startFunction() const { return StartFunction; } uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } + uint32_t getNumImportedTables() const { return NumImportedTables; } uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } uint32_t getNumImportedEvents() const { return NumImportedEvents; } uint32_t getNumSections() const { return Sections.size(); } @@ -214,7 +216,9 @@ bool isValidFunctionIndex(uint32_t Index) const; bool isDefinedFunctionIndex(uint32_t Index) const; bool isValidGlobalIndex(uint32_t Index) const; + bool isValidTableIndex(uint32_t Index) const; bool isDefinedGlobalIndex(uint32_t Index) const; + bool isDefinedTableIndex(uint32_t Index) const; bool isValidEventIndex(uint32_t Index) const; bool isDefinedEventIndex(uint32_t Index) const; bool isValidFunctionSymbol(uint32_t Index) const; @@ -285,6 +289,7 @@ bool HasMemory64 = false; wasm::WasmLinkingData LinkingData; uint32_t NumImportedGlobals = 0; + uint32_t NumImportedTables = 0; uint32_t NumImportedFunctions = 0; uint32_t NumImportedEvents = 0; uint32_t CodeSection = 0; diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h --- a/llvm/include/llvm/ObjectYAML/WasmYAML.h +++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h @@ -53,6 +53,7 @@ struct Table { TableType ElemType; Limits TableLimits; + uint32_t Index; }; struct Export { diff --git a/llvm/lib/BinaryFormat/Wasm.cpp b/llvm/lib/BinaryFormat/Wasm.cpp --- a/llvm/lib/BinaryFormat/Wasm.cpp +++ b/llvm/lib/BinaryFormat/Wasm.cpp @@ -14,6 +14,8 @@ return "WASM_SYMBOL_TYPE_FUNCTION"; case wasm::WASM_SYMBOL_TYPE_GLOBAL: return "WASM_SYMBOL_TYPE_GLOBAL"; + case wasm::WASM_SYMBOL_TYPE_TABLE: + return "WASM_SYMBOL_TYPE_TABLE"; case wasm::WASM_SYMBOL_TYPE_DATA: return "WASM_SYMBOL_TYPE_DATA"; case wasm::WASM_SYMBOL_TYPE_SECTION: diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -194,8 +194,8 @@ // Maps function symbols to the table element index space. Used // for TABLE_INDEX relocation types (i.e. address taken functions). DenseMap TableIndices; - // Maps function/global symbols to the function/global/event/section index - // space. + // Maps function/global/table symbols to the + // function/global/table/event/section index space. DenseMap WasmIndices; DenseMap GOTIndices; // Maps data symbols to the Wasm segment and offset/size with the segment. @@ -218,6 +218,9 @@ SmallVector DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; + // NumTableImports is initialized to 1 to account for the hardcoded import of + // __indirect_function_table + unsigned NumTableImports = 1; unsigned NumEventImports = 0; uint32_t SectionCount = 0; @@ -267,6 +270,7 @@ SectionFunctions.clear(); NumFunctionImports = 0; NumGlobalImports = 0; + NumTableImports = 1; MCObjectWriter::reset(); } @@ -316,6 +320,7 @@ uint32_t writeDataSection(const MCAsmLayout &Layout); void writeEventSection(ArrayRef Events); void writeGlobalSection(ArrayRef Globals); + void writeTableSection(ArrayRef Tables); void writeRelocSection(uint32_t SectionIndex, StringRef Name, std::vector &Relocations); void writeLinkingMetaDataSection( @@ -827,6 +832,24 @@ endSection(Section); } +void WasmObjectWriter::writeTableSection(ArrayRef Tables) { + if (Tables.empty()) + return; + + SectionBookkeeping Section; + startSection(Section, wasm::WASM_SEC_TABLE); + + encodeULEB128(Tables.size(), W->OS); + for (const wasm::WasmTable &Table : Tables) { + encodeULEB128(Table.ElemType, W->OS); + encodeULEB128(Table.Limits.Flags, W->OS); + encodeULEB128(Table.Limits.Initial, W->OS); + if (Table.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) + encodeULEB128(Table.Limits.Maximum, W->OS); + } + endSection(Section); +} + void WasmObjectWriter::writeExportSection(ArrayRef Exports) { if (Exports.empty()) return; @@ -1003,6 +1026,7 @@ case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: case wasm::WASM_SYMBOL_TYPE_EVENT: + case wasm::WASM_SYMBOL_TYPE_TABLE: encodeULEB128(Sym.ElementIndex, W->OS); if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 || (Sym.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) @@ -1292,6 +1316,7 @@ SmallVector Exports; SmallVector Events; SmallVector Globals; + SmallVector Tables; SmallVector SymbolInfos; SmallVector, 2> InitFuncs; std::map> Comdats; @@ -1494,6 +1519,20 @@ LLVM_DEBUG(dbgs() << " -> global index: " << WasmIndices.find(&WS)->second << "\n"); } + } else if (WS.isTable()) { + if (WS.isDefined()) { + assert(WasmIndices.count(&WS) == 0); + wasm::WasmTable Table; + Table.ElemType = static_cast(WS.getTableType()); + Table.Index = NumTableImports + Tables.size(); + // FIXME: Work on custom limits is ongoing + Table.Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; + + WasmIndices[&WS] = Table.Index; + Tables.push_back(Table); + } + LLVM_DEBUG(dbgs() << " -> table index: " << WasmIndices.find(&WS)->second + << "\n"); } else if (WS.isEvent()) { // C++ exception symbol (__cpp_exception) unsigned Index; @@ -1715,10 +1754,10 @@ writeTypeSection(Signatures); writeImportSection(Imports, DataSize, TableElems.size()); writeFunctionSection(Functions); - // Skip the "table" section; we import the table instead. // Skip the "memory" section; we import the memory instead. writeEventSection(Events); writeGlobalSection(Globals); + writeTableSection(Tables); writeExportSection(Exports); writeElemSection(TableElems); writeDataCountSection(); diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -218,6 +218,7 @@ wasm::WasmTable Table; Table.ElemType = readUint8(Ctx); Table.Limits = readLimits(Ctx); + // The caller needs to set Table.Index field for Table return Table; } @@ -499,6 +500,7 @@ wasm::WasmSymbolInfo Info; const wasm::WasmSignature *Signature = nullptr; const wasm::WasmGlobalType *GlobalType = nullptr; + uint8_t TableType = 0; const wasm::WasmEventType *EventType = nullptr; Info.Kind = readUint8(Ctx); @@ -567,6 +569,27 @@ } break; + case wasm::WASM_SYMBOL_TYPE_TABLE: + Info.ElementIndex = readVaruint32(Ctx); + if (!isValidTableIndex(Info.ElementIndex) || + IsDefined != isDefinedTableIndex(Info.ElementIndex)) + return make_error("invalid table symbol index", + object_error::parse_failed); + if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) == + wasm::WASM_SYMBOL_BINDING_WEAK) + return make_error("undefined weak table symbol", + object_error::parse_failed); + if (IsDefined) { + Info.Name = readString(Ctx); + unsigned TableIndex = Info.ElementIndex - NumImportedTables; + wasm::WasmTable &Table = Tables[TableIndex]; + TableType = Table.ElemType; + } else { + return make_error("undefined table symbol", + object_error::parse_failed); + } + break; + case wasm::WASM_SYMBOL_TYPE_DATA: Info.Name = readString(Ctx); if (IsDefined) { @@ -644,8 +667,8 @@ Twine(Info.Name), object_error::parse_failed); LinkingData.SymbolTable.emplace_back(Info); - Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, EventType, - Signature); + Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType, + EventType, Signature); LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n"); } @@ -963,12 +986,17 @@ if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64) HasMemory64 = true; break; - case wasm::WASM_EXTERNAL_TABLE: + case wasm::WASM_EXTERNAL_TABLE: { Im.Table = readTable(Ctx); - if (Im.Table.ElemType != wasm::WASM_TYPE_FUNCREF) + Im.Table.Index = NumImportedTables + Tables.size(); + NumImportedTables++; + auto ElemType = Im.Table.ElemType; + if (ElemType != wasm::WASM_TYPE_FUNCREF && + ElemType != wasm::WASM_TYPE_EXTERNREF) return make_error("Invalid table element type", object_error::parse_failed); break; + } case wasm::WASM_EXTERNAL_EVENT: NumImportedEvents++; Im.Event.Attribute = readVarint32(Ctx); @@ -1008,8 +1036,12 @@ uint32_t Count = readVaruint32(Ctx); Tables.reserve(Count); while (Count--) { - Tables.push_back(readTable(Ctx)); - if (Tables.back().ElemType != wasm::WASM_TYPE_FUNCREF) { + wasm::WasmTable T = readTable(Ctx); + T.Index = NumImportedTables + Tables.size(); + Tables.push_back(T); + auto ElemType = Tables.back().ElemType; + if (ElemType != wasm::WASM_TYPE_FUNCREF && + ElemType != wasm::WASM_TYPE_EXTERNREF) { return make_error("Invalid table element type", object_error::parse_failed); } @@ -1125,10 +1157,18 @@ return Index < NumImportedGlobals + Globals.size(); } +bool WasmObjectFile::isValidTableIndex(uint32_t Index) const { + return Index < NumImportedTables + Tables.size(); +} + bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const { return Index >= NumImportedGlobals && isValidGlobalIndex(Index); } +bool WasmObjectFile::isDefinedTableIndex(uint32_t Index) const { + return Index >= NumImportedTables && isValidTableIndex(Index); +} + bool WasmObjectFile::isValidEventIndex(uint32_t Index) const { return Index < NumImportedEvents + Events.size(); } diff --git a/llvm/lib/ObjectYAML/WasmEmitter.cpp b/llvm/lib/ObjectYAML/WasmEmitter.cpp --- a/llvm/lib/ObjectYAML/WasmEmitter.cpp +++ b/llvm/lib/ObjectYAML/WasmEmitter.cpp @@ -60,6 +60,7 @@ WasmYAML::Object &Obj; uint32_t NumImportedFunctions = 0; uint32_t NumImportedGlobals = 0; + uint32_t NumImportedTables = 0; uint32_t NumImportedEvents = 0; bool HasError = false; @@ -187,6 +188,7 @@ switch (Info.Kind) { case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_TABLE: case wasm::WASM_SYMBOL_TYPE_EVENT: encodeULEB128(Info.ElementIndex, SubSection.getStream()); if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0 || @@ -360,7 +362,7 @@ case wasm::WASM_EXTERNAL_EVENT: writeUint32(OS, Import.EventImport.Attribute); writeUint32(OS, Import.EventImport.SigIndex); - NumImportedGlobals++; + NumImportedEvents++; break; case wasm::WASM_EXTERNAL_MEMORY: writeLimits(Import.Memory, OS); @@ -368,6 +370,7 @@ case wasm::WASM_EXTERNAL_TABLE: writeUint8(OS, Import.TableImport.ElemType); writeLimits(Import.TableImport.TableLimits, OS); + NumImportedTables++; break; default: reportError("unknown import type: " +Twine(Import.Kind)); @@ -401,7 +404,13 @@ void WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::TableSection &Section) { encodeULEB128(Section.Tables.size(), OS); + uint32_t ExpectedIndex = NumImportedTables; for (auto &Table : Section.Tables) { + if (Table.Index != ExpectedIndex) { + reportError("unexpected table index: " + Twine(Table.Index)); + return; + } + ++ExpectedIndex; writeUint8(OS, Table.ElemType); writeLimits(Table.TableLimits, OS); } diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -300,6 +300,7 @@ } void MappingTraits::mapping(IO &IO, WasmYAML::Table &Table) { + IO.mapRequired("Index", Table.Index); IO.mapRequired("ElemType", Table.ElemType); IO.mapRequired("Limits", Table.TableLimits); } @@ -496,6 +497,8 @@ IO.mapRequired("Function", Info.ElementIndex); } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL) { IO.mapRequired("Global", Info.ElementIndex); + } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_TABLE) { + IO.mapRequired("Table", Info.ElementIndex); } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT) { IO.mapRequired("Event", Info.ElementIndex); } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA) { @@ -551,6 +554,7 @@ ECase(FUNCTION); ECase(DATA); ECase(GLOBAL); + ECase(TABLE); ECase(SECTION); ECase(EVENT); #undef ECase @@ -599,6 +603,7 @@ IO &IO, WasmYAML::TableType &Type) { #define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); ECase(FUNCREF); + ECase(EXTERNREF); #undef ECase } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -324,6 +324,8 @@ return wasm::ValType::V128; if (Type == "exnref") return wasm::ValType::EXNREF; + if (Type == "funcref") + return wasm::ValType::FUNCREF; if (Type == "externref") return wasm::ValType::EXTERNREF; return Optional(); @@ -712,6 +714,29 @@ return expect(AsmToken::EndOfStatement, "EOL"); } + if (DirectiveID.getString() == ".tabletype") { + auto SymName = expectIdent(); + if (SymName.empty()) + return true; + if (expect(AsmToken::Comma, ",")) + return true; + auto TypeTok = Lexer.getTok(); + auto TypeName = expectIdent(); + if (TypeName.empty()) + return true; + auto Type = parseType(TypeName); + if (!Type) + return error("Unknown type in .tabletype directive: ", TypeTok); + + // Now that we have the name and table type, we can actually create the + // symbol + auto WasmSym = cast(Ctx.getOrCreateSymbol(SymName)); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); + WasmSym->setTableType(Type.getValue()); + TOut.emitTableType(WasmSym); + return expect(AsmToken::EndOfStatement, "EOL"); + } + if (DirectiveID.getString() == ".functype") { // This code has to send things to the streamer similar to // WebAssemblyAsmPrinter::EmitFunctionBodyStart. diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyInstPrinter.cpp @@ -318,6 +318,8 @@ return "v128"; case wasm::WASM_TYPE_FUNCREF: return "funcref"; + case wasm::WASM_TYPE_EXTERNREF: + return "externref"; case wasm::WASM_TYPE_FUNC: return "func"; case wasm::WASM_TYPE_EXNREF: diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -39,6 +39,8 @@ virtual void emitIndIdx(const MCExpr *Value) = 0; /// .globaltype virtual void emitGlobalType(const MCSymbolWasm *Sym) = 0; + /// .tabletype + virtual void emitTableType(const MCSymbolWasm *Sym) = 0; /// .eventtype virtual void emitEventType(const MCSymbolWasm *Sym) = 0; /// .import_module @@ -67,6 +69,7 @@ void emitFunctionType(const MCSymbolWasm *Sym) override; void emitIndIdx(const MCExpr *Value) override; void emitGlobalType(const MCSymbolWasm *Sym) override; + void emitTableType(const MCSymbolWasm *Sym) override; void emitEventType(const MCSymbolWasm *Sym) override; void emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule) override; void emitImportName(const MCSymbolWasm *Sym, StringRef ImportName) override; @@ -83,6 +86,7 @@ void emitFunctionType(const MCSymbolWasm *Sym) override {} void emitIndIdx(const MCExpr *Value) override; void emitGlobalType(const MCSymbolWasm *Sym) override {} + void emitTableType(const MCSymbolWasm *Sym) override {} void emitEventType(const MCSymbolWasm *Sym) override {} void emitImportModule(const MCSymbolWasm *Sym, StringRef ImportModule) override {} @@ -103,6 +107,7 @@ void emitFunctionType(const MCSymbolWasm *) override {} void emitIndIdx(const MCExpr *) override {} void emitGlobalType(const MCSymbolWasm *) override {} + void emitTableType(const MCSymbolWasm *) override {} void emitEventType(const MCSymbolWasm *) override {} void emitImportModule(const MCSymbolWasm *, StringRef) override {} void emitImportName(const MCSymbolWasm *, StringRef) override {} diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -77,6 +77,13 @@ OS << '\n'; } +void WebAssemblyTargetAsmStreamer::emitTableType(const MCSymbolWasm *Sym) { + assert(Sym->isTable()); + OS << "\t.tabletype\t" << Sym->getName() << ", " + << WebAssembly::typeToString(Sym->getTableType()); + OS << '\n'; +} + void WebAssemblyTargetAsmStreamer::emitEventType(const MCSymbolWasm *Sym) { assert(Sym->isEvent()); OS << "\t.eventtype\t" << Sym->getName() << " "; diff --git a/llvm/test/MC/WebAssembly/assembler-binary.ll b/llvm/test/MC/WebAssembly/assembler-binary.ll --- a/llvm/test/MC/WebAssembly/assembler-binary.ll +++ b/llvm/test/MC/WebAssembly/assembler-binary.ll @@ -55,6 +55,7 @@ ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000000 diff --git a/llvm/test/MC/WebAssembly/basic-assembly.s b/llvm/test/MC/WebAssembly/basic-assembly.s --- a/llvm/test/MC/WebAssembly/basic-assembly.s +++ b/llvm/test/MC/WebAssembly/basic-assembly.s @@ -121,6 +121,13 @@ .ident "clang version 9.0.0 (trunk 364502) (llvm/trunk 364571)" .globaltype __stack_pointer, i32 +.tabletype empty_eref_table, externref +empty_eref_table: + +.tabletype empty_fref_table, funcref +empty_fref_table: + + # CHECK: .text # CHECK-LABEL: empty_func: # CHECK-NEXT: .functype empty_func () -> () @@ -228,3 +235,9 @@ # CHECK-NEXT: .int32 test0 # CHECK: .globaltype __stack_pointer, i32 + +# CHECK: .tabletype empty_eref_table, externref +# CHECK-NEXT: empty_eref_table: + +# CHECK: .tabletype empty_fref_table, funcref +# CHECK-NEXT: empty_fref_table: diff --git a/llvm/test/MC/WebAssembly/comdat.ll b/llvm/test/MC/WebAssembly/comdat.ll --- a/llvm/test/MC/WebAssembly/comdat.ll +++ b/llvm/test/MC/WebAssembly/comdat.ll @@ -42,6 +42,7 @@ ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000000 diff --git a/llvm/test/MC/WebAssembly/data-section.s b/llvm/test/MC/WebAssembly/data-section.s --- a/llvm/test/MC/WebAssembly/data-section.s +++ b/llvm/test/MC/WebAssembly/data-section.s @@ -49,6 +49,7 @@ # BIN-NEXT: Field: __indirect_function_table # BIN-NEXT: Kind: TABLE # BIN-NEXT: Table: +# BIN-NEXT: Index: 0 # BIN-NEXT: ElemType: FUNCREF # BIN-NEXT: Limits: # BIN-NEXT: Initial: 0x00000000 diff --git a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll --- a/llvm/test/MC/WebAssembly/global-ctor-dtor.ll +++ b/llvm/test/MC/WebAssembly/global-ctor-dtor.ll @@ -30,6 +30,7 @@ ; CHECK-NEXT: Field: __indirect_function_table ; CHECK-NEXT: Kind: TABLE ; CHECK-NEXT: Table: +; CHECK-NEXT: Index: 0 ; CHECK-NEXT: ElemType: FUNCREF ; CHECK-NEXT: Limits: ; CHECK-NEXT: Initial: 0x00000002 diff --git a/llvm/test/MC/WebAssembly/reloc-pic.s b/llvm/test/MC/WebAssembly/reloc-pic.s --- a/llvm/test/MC/WebAssembly/reloc-pic.s +++ b/llvm/test/MC/WebAssembly/reloc-pic.s @@ -66,6 +66,7 @@ # CHECK-NEXT: Field: __indirect_function_table # CHECK-NEXT: Kind: TABLE # CHECK-NEXT: Table: +# CHECK-NEXT: Index: 0 # CHECK-NEXT: ElemType: FUNCREF # CHECK-NEXT: Limits: # CHECK-NEXT: Initial: 0x00000001 diff --git a/llvm/test/MC/WebAssembly/tables.s b/llvm/test/MC/WebAssembly/tables.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/WebAssembly/tables.s @@ -0,0 +1,42 @@ +# RUN: llvm-mc -triple=wasm32-unknown-unknown < %s | FileCheck %s +# RUN: llvm-mc -triple=wasm32-unknown-unknown -filetype=obj < %s | obj2yaml | FileCheck -check-prefix=BIN %s + +# Test creating several empty tables + +.tabletype foo, externref +foo: + +bar: +.tabletype bar, funcref + +# CHECK: .tabletype foo, externref +# CHECK: foo: + +# CHECK: bar: +# CHECK-NEXT: .tabletype bar, funcref + +# BIN: - Type: TABLE +# BIN-NEXT: Tables: +# BIN-NEXT: - ElemType: EXTERNREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x00000000 +# BIN-NEXT: Index: 1 +# BIN-NEXT: - ElemType: FUNCREF +# BIN-NEXT: Limits: +# BIN-NEXT: Initial: 0x00000000 +# BIN-NEXT: Index: 2 + +# BIN: - Type: CUSTOM +# BIN-NEXT: Name: linking +# BIN-NEXT: Version: 2 +# BIN-NEXT: SymbolTable: +# BIN-NEXT: - Index: 0 +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Name: foo +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Table: 1 +# BIN-NEXT: - Index: 1 +# BIN-NEXT: Kind: TABLE +# BIN-NEXT: Name: bar +# BIN-NEXT: Flags: [ BINDING_LOCAL ] +# BIN-NEXT: Table: 2 diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp --- a/llvm/tools/obj2yaml/wasm2yaml.cpp +++ b/llvm/tools/obj2yaml/wasm2yaml.cpp @@ -37,6 +37,7 @@ T.TableLimits.Flags = Table.Limits.Flags; T.TableLimits.Initial = Table.Limits.Initial; T.TableLimits.Maximum = Table.Limits.Maximum; + T.Index = Table.Index; return T; } @@ -116,6 +117,7 @@ break; case wasm::WASM_SYMBOL_TYPE_FUNCTION: case wasm::WASM_SYMBOL_TYPE_GLOBAL: + case wasm::WASM_SYMBOL_TYPE_TABLE: case wasm::WASM_SYMBOL_TYPE_EVENT: Info.ElementIndex = Symbol.ElementIndex; break;