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:
parent
14d56a77f5
commit
df20558925
@ -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 = '+',
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
123
test/ObjectYAML/wasm/multiple-tables.yaml
Normal file
123
test/ObjectYAML/wasm/multiple-tables.yaml
Normal 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: ...
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user