1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[WebAssembly][yaml2obj][obj2yaml] Elem sections for nonzero tables

With reference types, tables can have non-zero table numbers.  This
commit adds support for element sections against these tables.

Differential Revision: https://reviews.llvm.org/D97923
This commit is contained in:
Andy Wingo 2021-03-04 10:30:00 +01:00
parent 14d56a77f5
commit df20558925
9 changed files with 244 additions and 22 deletions

View File

@ -159,7 +159,9 @@ struct WasmDataSegment {
};
struct WasmElemSegment {
uint32_t TableIndex;
uint32_t Flags;
uint32_t TableNumber;
uint8_t ElemKind;
WasmInitExpr Offset;
std::vector<uint32_t> Functions;
};
@ -307,6 +309,13 @@ enum : unsigned {
WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,
};
enum : unsigned {
WASM_ELEM_SEGMENT_IS_PASSIVE = 0x01,
WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02,
WASM_ELEM_SEGMENT_HAS_INIT_EXPRS = 0x04,
};
const unsigned WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND = 0x3;
// Feature policy prefixes used in the custom "target_features" section
enum : uint8_t {
WASM_FEATURE_PREFIX_USED = '+',

View File

@ -220,9 +220,9 @@ private:
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 isValidTableNumber(uint32_t Index) const;
bool isDefinedGlobalIndex(uint32_t Index) const;
bool isDefinedTableIndex(uint32_t Index) const;
bool isDefinedTableNumber(uint32_t Index) const;
bool isValidEventIndex(uint32_t Index) const;
bool isDefinedEventIndex(uint32_t Index) const;
bool isValidFunctionSymbol(uint32_t Index) const;

View File

@ -63,7 +63,9 @@ struct Export {
};
struct ElemSegment {
uint32_t TableIndex;
uint32_t Flags;
uint32_t TableNumber;
ValueType ElemKind;
wasm::WasmInitExpr Offset;
std::vector<uint32_t> Functions;
};

View File

@ -311,7 +311,8 @@ private:
uint32_t NumElements);
void writeFunctionSection(ArrayRef<WasmFunction> Functions);
void writeExportSection(ArrayRef<wasm::WasmExport> Exports);
void writeElemSection(ArrayRef<uint32_t> TableElems);
void writeElemSection(const MCSymbolWasm *IndirectFunctionTable,
ArrayRef<uint32_t> TableElems);
void writeDataCountSection();
uint32_t writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout,
ArrayRef<WasmFunction> Functions);
@ -902,21 +903,39 @@ void WasmObjectWriter::writeExportSection(ArrayRef<wasm::WasmExport> Exports) {
endSection(Section);
}
void WasmObjectWriter::writeElemSection(ArrayRef<uint32_t> TableElems) {
void WasmObjectWriter::writeElemSection(
const MCSymbolWasm *IndirectFunctionTable, ArrayRef<uint32_t> TableElems) {
if (TableElems.empty())
return;
assert(IndirectFunctionTable);
SectionBookkeeping Section;
startSection(Section, wasm::WASM_SEC_ELEM);
encodeULEB128(1, W->OS); // number of "segments"
encodeULEB128(0, W->OS); // the table index
assert(WasmIndices.count(IndirectFunctionTable));
uint32_t TableNumber = WasmIndices.find(IndirectFunctionTable)->second;
uint32_t Flags = 0;
if (TableNumber)
Flags |= wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER;
encodeULEB128(Flags, W->OS);
if (Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
encodeULEB128(TableNumber, W->OS); // the table number
// init expr for starting offset
W->OS << char(wasm::WASM_OPCODE_I32_CONST);
encodeSLEB128(InitialTableOffset, W->OS);
W->OS << char(wasm::WASM_OPCODE_END);
if (Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
// We only write active function table initializers, for which the elem kind
// is specified to be written as 0x00 and interpreted to mean "funcref".
const uint8_t ElemKind = 0;
W->OS << ElemKind;
}
encodeULEB128(TableElems.size(), W->OS);
for (uint32_t Elem : TableElems)
encodeULEB128(Elem, W->OS);
@ -1824,7 +1843,10 @@ uint64_t WasmObjectWriter::writeOneObject(MCAssembler &Asm,
writeEventSection(Events);
writeGlobalSection(Globals);
writeExportSection(Exports);
writeElemSection(TableElems);
const MCSymbol *IndirectFunctionTable =
Asm.getContext().lookupSymbol("__indirect_function_table");
writeElemSection(cast_or_null<const MCSymbolWasm>(IndirectFunctionTable),
TableElems);
writeDataCountSection();
CodeSectionIndex = writeCodeSection(Asm, Layout, Functions);

View File

@ -598,8 +598,8 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
case wasm::WASM_SYMBOL_TYPE_TABLE:
Info.ElementIndex = readVaruint32(Ctx);
if (!isValidTableIndex(Info.ElementIndex) ||
IsDefined != isDefinedTableIndex(Info.ElementIndex))
if (!isValidTableNumber(Info.ElementIndex) ||
IsDefined != isDefinedTableNumber(Info.ElementIndex))
return make_error<GenericBinaryError>("invalid table symbol index",
object_error::parse_failed);
if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
@ -608,8 +608,8 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
object_error::parse_failed);
if (IsDefined) {
Info.Name = readString(Ctx);
unsigned TableIndex = Info.ElementIndex - NumImportedTables;
wasm::WasmTable &Table = Tables[TableIndex];
unsigned TableNumber = Info.ElementIndex - NumImportedTables;
wasm::WasmTable &Table = Tables[TableNumber];
TableType = &Table.Type;
if (Table.SymbolName.empty())
Table.SymbolName = Info.Name;
@ -1220,7 +1220,7 @@ bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
return Index < NumImportedGlobals + Globals.size();
}
bool WasmObjectFile::isValidTableIndex(uint32_t Index) const {
bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
return Index < NumImportedTables + Tables.size();
}
@ -1228,8 +1228,8 @@ 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::isDefinedTableNumber(uint32_t Index) const {
return Index >= NumImportedTables && isValidTableNumber(Index);
}
bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
@ -1340,13 +1340,54 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
ElemSegments.reserve(Count);
while (Count--) {
wasm::WasmElemSegment Segment;
Segment.TableIndex = readVaruint32(Ctx);
if (Segment.TableIndex != 0) {
return make_error<GenericBinaryError>("invalid TableIndex",
Segment.Flags = readVaruint32(Ctx);
uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
if (Segment.Flags & ~SupportedFlags)
return make_error<GenericBinaryError>(
"Unsupported flags for element segment", object_error::parse_failed);
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
Segment.TableNumber = readVaruint32(Ctx);
else
Segment.TableNumber = 0;
if (!isValidTableNumber(Segment.TableNumber))
return make_error<GenericBinaryError>("invalid TableNumber",
object_error::parse_failed);
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
Segment.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
Segment.Offset.Value.Int32 = 0;
} else {
if (Error Err = readInitExpr(Segment.Offset, Ctx))
return Err;
}
if (Error Err = readInitExpr(Segment.Offset, Ctx))
return Err;
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
Segment.ElemKind = readUint8(Ctx);
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
return make_error<GenericBinaryError>("invalid reference type",
object_error::parse_failed);
}
} else {
if (Segment.ElemKind != 0)
return make_error<GenericBinaryError>("invalid elemtype",
object_error::parse_failed);
Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
}
} else {
Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
}
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
return make_error<GenericBinaryError>(
"elem segment init expressions not yet implemented",
object_error::parse_failed);
uint32_t NumElems = readVaruint32(Ctx);
while (NumElems--) {
Segment.Functions.push_back(readVaruint32(Ctx));

View File

@ -484,9 +484,24 @@ void WasmWriter::writeSectionContent(raw_ostream &OS,
WasmYAML::ElemSection &Section) {
encodeULEB128(Section.Segments.size(), OS);
for (auto &Segment : Section.Segments) {
encodeULEB128(Segment.TableIndex, OS);
encodeULEB128(Segment.Flags, OS);
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
encodeULEB128(Segment.TableNumber, OS);
writeInitExpr(OS, Segment.Offset);
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
// We only support active function table initializers, for which the elem
// kind is specified to be written as 0x00 and interpreted to mean
// "funcref".
if (Segment.ElemKind != uint32_t(wasm::ValType::FUNCREF)) {
reportError("unexpected elemkind: " + Twine(Segment.ElemKind));
return;
}
const uint8_t ElemKind = 0;
writeUint8(OS, ElemKind);
}
encodeULEB128(Segment.Functions.size(), OS);
for (auto &Function : Segment.Functions)
encodeULEB128(Function, OS);

View File

@ -374,6 +374,14 @@ void MappingTraits<WasmYAML::Limits>::mapping(IO &IO,
void MappingTraits<WasmYAML::ElemSegment>::mapping(
IO &IO, WasmYAML::ElemSegment &Segment) {
if (!IO.outputting() || Segment.Flags)
IO.mapOptional("Flags", Segment.Flags);
if (!IO.outputting() ||
Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
IO.mapOptional("TableNumber", Segment.TableNumber);
if (!IO.outputting() ||
Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND)
IO.mapOptional("ElemKind", Segment.ElemKind);
IO.mapRequired("Offset", Segment.Offset);
IO.mapRequired("Functions", Segment.Functions);
}

View File

@ -0,0 +1,123 @@
# RUN: yaml2obj %s | obj2yaml | FileCheck %s
--- !WASM
FileHeader:
Version: 0x1
Sections:
- Type: TYPE
Signatures:
- Index: 0
ParamTypes: []
ReturnTypes: []
- Type: IMPORT
Imports:
- Module: env
Field: table_a
Kind: TABLE
Table:
Index: 0
ElemType: FUNCREF
Limits:
Initial: 0x0
- Type: FUNCTION
FunctionTypes: [ 0 ]
- Type: TABLE
Tables:
- Index: 1
ElemType: FUNCREF
Limits:
Initial: 0x0
- Index: 2
ElemType: EXTERNREF
Limits:
Initial: 0x0
- Index: 3
ElemType: FUNCREF
Limits:
Flags: [ HAS_MAX ]
Initial: 0x3
Maximum: 0x3
- Type: EXPORT
Exports:
- Name: table_b
Kind: TABLE
Index: 1
- Name: table_c
Kind: TABLE
Index: 2
- Type: ELEM
Segments:
- Flags: 2
TableNumber: 3
ElemKind: FUNCREF
Offset:
Opcode: I32_CONST
Value: 1
Functions: [ 0, 0 ]
- Type: CODE
Functions:
- Index: 0
Locals: []
Body: 0B
...
# CHECK: --- !WASM
# CHECK-NEXT: FileHeader:
# CHECK-NEXT: Version: 0x1
# CHECK-NEXT: Sections:
# CHECK-NEXT: - Type: TYPE
# CHECK-NEXT: Signatures:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: ParamTypes: []
# CHECK-NEXT: ReturnTypes: []
# CHECK-NEXT: - Type: IMPORT
# CHECK-NEXT: Imports:
# CHECK-NEXT: - Module: env
# CHECK-NEXT: Field: table_a
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Table:
# CHECK-NEXT: Index: 0
# CHECK-NEXT: ElemType: FUNCREF
# CHECK-NEXT: Limits:
# CHECK-NEXT: Initial: 0x0
# CHECK-NEXT: - Type: FUNCTION
# CHECK-NEXT: FunctionTypes: [ 0 ]
# CHECK-NEXT: - Type: TABLE
# CHECK-NEXT: Tables:
# CHECK-NEXT: - Index: 1
# CHECK-NEXT: ElemType: FUNCREF
# CHECK-NEXT: Limits:
# CHECK-NEXT: Initial: 0x0
# CHECK-NEXT: - Index: 2
# CHECK-NEXT: ElemType: EXTERNREF
# CHECK-NEXT: Limits:
# CHECK-NEXT: Initial: 0x0
# CHECK-NEXT: - Index: 3
# CHECK-NEXT: ElemType: FUNCREF
# CHECK-NEXT: Limits:
# CHECK-NEXT: Flags: [ HAS_MAX ]
# CHECK-NEXT: Initial: 0x3
# CHECK-NEXT: Maximum: 0x3
# CHECK-NEXT: - Type: EXPORT
# CHECK-NEXT: Exports:
# CHECK-NEXT: - Name: table_b
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Index: 1
# CHECK-NEXT: - Name: table_c
# CHECK-NEXT: Kind: TABLE
# CHECK-NEXT: Index: 2
# CHECK-NEXT: - Type: ELEM
# CHECK-NEXT: Segments:
# CHECK-NEXT: - Flags: 2
# CHECK-NEXT: TableNumber: 3
# CHECK-NEXT: ElemKind: FUNCREF
# CHECK-NEXT: Offset:
# CHECK-NEXT: Opcode: I32_CONST
# CHECK-NEXT: Value: 1
# CHECK-NEXT: Functions: [ 0, 0 ]
# CHECK-NEXT: - Type: CODE
# CHECK-NEXT: Functions:
# CHECK-NEXT: - Index: 0
# CHECK-NEXT: Locals: []
# CHECK-NEXT: Body: 0B
# CHECK-NEXT: ...

View File

@ -327,7 +327,9 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() {
auto ElemSec = std::make_unique<WasmYAML::ElemSection>();
for (auto &Segment : Obj.elements()) {
WasmYAML::ElemSegment Seg;
Seg.TableIndex = Segment.TableIndex;
Seg.Flags = Segment.Flags;
Seg.TableNumber = Segment.TableNumber;
Seg.ElemKind = Segment.ElemKind;
Seg.Offset = Segment.Offset;
append_range(Seg.Functions, Segment.Functions);
ElemSec->Segments.push_back(Seg);