https://github.com/dschuff updated https://github.com/llvm/llvm-project/pull/79235
>From 976c98f631e5ed48bb18accbe59c9babd354a924 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Wed, 3 Jan 2024 09:06:37 -0800 Subject: [PATCH 01/12] parse types --- llvm/include/llvm/BinaryFormat/Wasm.h | 8 +++ llvm/lib/Object/WasmObjectFile.cpp | 83 +++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index c7658cc7b7432b3..89499a61b76c8c3 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -265,7 +265,13 @@ enum : unsigned { WASM_TYPE_V128 = 0x7B, WASM_TYPE_FUNCREF = 0x70, WASM_TYPE_EXTERNREF = 0x6F, + WASM_TYPE_NULLABLE = 0x63, WASM_TYPE_FUNC = 0x60, + WASM_TYPE_ARRAY = 0x5E, // Composite types, not used for codegen + WASM_TYPE_STRUCT = 0x5F, + WASM_TYPE_SUB = 0x50, + WASM_TYPE_SUB_FINAL = 0x4F, + WASM_TYPE_REC = 0x4E, WASM_TYPE_NORESULT = 0x40, // for blocks with no result values }; @@ -431,11 +437,13 @@ enum class ValType { V128 = WASM_TYPE_V128, FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, + OTHERREF, }; struct WasmSignature { SmallVector<ValType, 1> Returns; SmallVector<ValType, 4> Params; + enum {Function, Other} Kind = Function; // Support empty and tombstone instances, needed by DenseMap. enum { Plain, Empty, Tombstone } State = Plain; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 94cd96968ff2010..3d2b06342481aa0 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/TargetParser/SubtargetFeature.h" @@ -29,6 +30,7 @@ #include <cassert> #include <cstdint> #include <cstring> +#include <sys/types.h> #define DEBUG_TYPE "wasm-object" @@ -1104,26 +1106,107 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) { } Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { + auto parseFieldDef = [&]() { + int32_t TypeCode = readVarint32((Ctx)); + uint32_t Mutability = readVaruint32(Ctx); + }; + auto parseRecType = [&]() { + uint8_t Form = readUint8(Ctx); + if (Form == wasm::WASM_TYPE_REC) { + uint32_t Size = readVaruint32(Ctx); + assert(Size > 0); // TODO real errors here and below + Form = readVaruint32(Ctx); + } + if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) { + uint32_t Supers = readVaruint32(Ctx); + if (Supers > 0) { + assert(Supers == 1); + uint32_t SuperIndex = readVaruint32(Ctx); + } + Form = readVaruint32(Ctx); + } + if (Form == wasm::WASM_TYPE_STRUCT) { + uint32_t NumFields = readVaruint32(Ctx); + for (size_t i = 0; i < NumFields; i++) { + parseFieldDef(); + } + } else if (Form == wasm::WASM_TYPE_ARRAY) { + parseFieldDef(); + } + + }; + auto parseParamType = [&](uint32_t code) -> wasm::ValType { + switch(code) { + case wasm::WASM_TYPE_I32: + case wasm::WASM_TYPE_I64: + case wasm::WASM_TYPE_F32: + case wasm::WASM_TYPE_F64: + case wasm::WASM_TYPE_V128: + case wasm::WASM_TYPE_FUNCREF: + case wasm::WASM_TYPE_EXTERNREF: + return wasm::ValType(code); + } + }; uint32_t Count = readVaruint32(Ctx); Signatures.reserve(Count); while (Count--) { wasm::WasmSignature Sig; uint8_t Form = readUint8(Ctx); + llvm::errs() << llvm::format("Top Count %d form %x", Count, Form) << '\n'; + if (Form == wasm::WASM_TYPE_REC) { + uint32_t Size = readVaruint32(Ctx); + assert(Size > 0); // TODO real errors here and below + Form = readVaruint32(Ctx); + wasm::WasmSignature s; s.Kind = s.Other; + Signatures.push_back(s); + Count--; + llvm::errs() << llvm::format(" Rec size %d form %x", Size, Form) << '\n'; + } if (Form != wasm::WASM_TYPE_FUNC) { + wasm::WasmSignature s; s.Kind = s.Other; + if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) { + uint32_t Supers = readVaruint32(Ctx); + if (Supers > 0) { + assert(Supers == 1); + uint32_t SuperIndex = readVaruint32(Ctx); + } + Form = readVaruint32(Ctx); + llvm::errs() << llvm::format(" Sub Supers %d form %x", Supers, Form) << '\n'; + } + if (Form == wasm::WASM_TYPE_STRUCT) { + uint32_t NumFields = readVaruint32(Ctx); + for (size_t i = 0; i < NumFields; i++) { + parseFieldDef(); + } + llvm::errs() << llvm::format(" Struct size %d", NumFields) << '\n'; + } else if (Form == wasm::WASM_TYPE_ARRAY) { + parseFieldDef(); + llvm::errs() << llvm::format("arr form %x", Form) << '\n'; + } else { + llvm::errs() << llvm::format(" bad form %x", Form) << '\n'; + return make_error<GenericBinaryError>("bad form", object_error::parse_failed); + } + Signatures.push_back(s); + continue; return make_error<GenericBinaryError>("invalid signature type", object_error::parse_failed); } + uint32_t ParamCount = readVaruint32(Ctx); Sig.Params.reserve(ParamCount); + llvm::errs() << llvm::format("param ct %d ", ParamCount); while (ParamCount--) { uint32_t ParamType = readUint8(Ctx); + if (ParamType == ) Sig.Params.push_back(wasm::ValType(ParamType)); } uint32_t ReturnCount = readVaruint32(Ctx); + llvm::errs() << llvm::format("return ct %d\n", ReturnCount); while (ReturnCount--) { uint32_t ReturnType = readUint8(Ctx); Sig.Returns.push_back(wasm::ValType(ReturnType)); } + Signatures.push_back(std::move(Sig)); } if (Ctx.Ptr != Ctx.End) >From 28273084c7b3f10dbff88ffe418e12d4e7c7c159 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Thu, 4 Jan 2024 11:07:38 -0800 Subject: [PATCH 02/12] type section working --- llvm/include/llvm/BinaryFormat/Wasm.h | 16 +++++++- llvm/lib/Object/WasmObjectFile.cpp | 59 +++++++++++---------------- 2 files changed, 38 insertions(+), 37 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 89499a61b76c8c3..2cfb69fcf8f8276 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -263,8 +263,18 @@ enum : unsigned { WASM_TYPE_F32 = 0x7D, WASM_TYPE_F64 = 0x7C, WASM_TYPE_V128 = 0x7B, + WASM_TYPE_NULLFUNCREF = 0x73, + WASM_TYPE_NULLEXTERNREF = 0x72, + WASM_TYPE_NULLREF = 0x71, WASM_TYPE_FUNCREF = 0x70, WASM_TYPE_EXTERNREF = 0x6F, + WASM_TYPE_ANYREF = 0x6E, + WASM_TYPE_EQREF = 0x6D, + WASM_TYPE_I31REF = 0x6C, + WASM_TYPE_STRUCTREF = 0x6B, + WASM_TYPE_ARRAYREF = 0x6A, + WASM_TYPE_EXNREF = 0x69, + WASM_TYPE_NONNULLABLE = 0x64, WASM_TYPE_NULLABLE = 0x63, WASM_TYPE_FUNC = 0x60, WASM_TYPE_ARRAY = 0x5E, // Composite types, not used for codegen @@ -437,13 +447,15 @@ enum class ValType { V128 = WASM_TYPE_V128, FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, - OTHERREF, + OTHERREF, // Unmodeled value types include ref types with heap types other than funcref or externref }; +// Represents anything that can be encoded in the type section, but only +// signatures are actually modeled. TODO: maybe refactor to make this explicit. struct WasmSignature { SmallVector<ValType, 1> Returns; SmallVector<ValType, 4> Params; - enum {Function, Other} Kind = Function; + enum {Function, Other} Kind = Function; // Recursive, Composite(Array,Struct), // Support empty and tombstone instances, needed by DenseMap. enum { Plain, Empty, Tombstone } State = Plain; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 3d2b06342481aa0..639d49b242694c9 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1106,37 +1106,11 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) { } Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { - auto parseFieldDef = [&]() { - int32_t TypeCode = readVarint32((Ctx)); - uint32_t Mutability = readVaruint32(Ctx); - }; - auto parseRecType = [&]() { - uint8_t Form = readUint8(Ctx); - if (Form == wasm::WASM_TYPE_REC) { - uint32_t Size = readVaruint32(Ctx); - assert(Size > 0); // TODO real errors here and below - Form = readVaruint32(Ctx); - } - if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) { - uint32_t Supers = readVaruint32(Ctx); - if (Supers > 0) { - assert(Supers == 1); - uint32_t SuperIndex = readVaruint32(Ctx); - } - Form = readVaruint32(Ctx); - } - if (Form == wasm::WASM_TYPE_STRUCT) { - uint32_t NumFields = readVaruint32(Ctx); - for (size_t i = 0; i < NumFields; i++) { - parseFieldDef(); - } - } else if (Form == wasm::WASM_TYPE_ARRAY) { - parseFieldDef(); - } - }; - auto parseParamType = [&](uint32_t code) -> wasm::ValType { - switch(code) { + auto parseValType = [&](uint32_t Code) -> wasm::ValType { + // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern) + llvm::errs() << llvm::format(" val type %x ", Code); + switch(Code) { case wasm::WASM_TYPE_I32: case wasm::WASM_TYPE_I64: case wasm::WASM_TYPE_F32: @@ -1144,9 +1118,20 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { case wasm::WASM_TYPE_V128: case wasm::WASM_TYPE_FUNCREF: case wasm::WASM_TYPE_EXTERNREF: - return wasm::ValType(code); + return wasm::ValType(Code); + } + if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { + readVarint64(Ctx); } + return wasm::ValType(wasm::ValType::OTHERREF); }; + auto parseFieldDef = [&]() { + uint32_t TypeCode = readVaruint32((Ctx)); + parseValType(TypeCode); + uint32_t Mutability = readVaruint32(Ctx); + llvm::errs() << llvm:: format(" mut %d ", Mutability); + }; + uint32_t Count = readVaruint32(Ctx); Signatures.reserve(Count); while (Count--) { @@ -1156,6 +1141,8 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { if (Form == wasm::WASM_TYPE_REC) { uint32_t Size = readVaruint32(Ctx); assert(Size > 0); // TODO real errors here and below + Signatures.reserve(Signatures.size() + Size); + Count += Size; Form = readVaruint32(Ctx); wasm::WasmSignature s; s.Kind = s.Other; Signatures.push_back(s); @@ -1197,17 +1184,19 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { llvm::errs() << llvm::format("param ct %d ", ParamCount); while (ParamCount--) { uint32_t ParamType = readUint8(Ctx); - if (ParamType == ) - Sig.Params.push_back(wasm::ValType(ParamType)); + Sig.Returns.push_back(parseValType(ParamType)); + continue; + } uint32_t ReturnCount = readVaruint32(Ctx); - llvm::errs() << llvm::format("return ct %d\n", ReturnCount); + llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount); while (ReturnCount--) { uint32_t ReturnType = readUint8(Ctx); - Sig.Returns.push_back(wasm::ValType(ReturnType)); + Sig.Returns.push_back(parseValType(ReturnType)); } Signatures.push_back(std::move(Sig)); + llvm::errs() << '\n'; } if (Ctx.Ptr != Ctx.End) return make_error<GenericBinaryError>("type section ended prematurely", >From e716a1470836d18af1a1032880ed1afec47f4aa5 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Thu, 4 Jan 2024 11:57:02 -0800 Subject: [PATCH 03/12] some cleanup --- llvm/lib/Object/WasmObjectFile.cpp | 43 +++++++++++++++--------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 639d49b242694c9..c7916fdebac85a0 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -30,7 +30,6 @@ #include <cassert> #include <cstdint> #include <cstring> -#include <sys/types.h> #define DEBUG_TYPE "wasm-object" @@ -1106,7 +1105,6 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) { } Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { - auto parseValType = [&](uint32_t Code) -> wasm::ValType { // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern) llvm::errs() << llvm::format(" val type %x ", Code); @@ -1121,13 +1119,13 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { return wasm::ValType(Code); } if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { - readVarint64(Ctx); + /* Discard HeapType */ readVarint64(Ctx); } return wasm::ValType(wasm::ValType::OTHERREF); }; auto parseFieldDef = [&]() { uint32_t TypeCode = readVaruint32((Ctx)); - parseValType(TypeCode); + /* Discard StorageType */ parseValType(TypeCode); uint32_t Mutability = readVaruint32(Ctx); llvm::errs() << llvm:: format(" mut %d ", Mutability); }; @@ -1139,33 +1137,36 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { uint8_t Form = readUint8(Ctx); llvm::errs() << llvm::format("Top Count %d form %x", Count, Form) << '\n'; if (Form == wasm::WASM_TYPE_REC) { - uint32_t Size = readVaruint32(Ctx); - assert(Size > 0); // TODO real errors here and below - Signatures.reserve(Signatures.size() + Size); - Count += Size; - Form = readVaruint32(Ctx); - wasm::WasmSignature s; s.Kind = s.Other; - Signatures.push_back(s); - Count--; - llvm::errs() << llvm::format(" Rec size %d form %x", Size, Form) << '\n'; + // Rec groups expand the type index space (beyond what was declared at + // the top of the section, and also consume one element in that space. + uint32_t RecSize = readVaruint32(Ctx); + assert(RecSize > 0); // TODO real errors here and below + Signatures.reserve(Signatures.size() + RecSize); + Count += RecSize; + llvm::errs() << llvm::format(" Rec size %d\n", RecSize); + Sig.Kind = wasm::WasmSignature::Other; + Signatures.push_back(std::move(Sig)); + continue; } if (Form != wasm::WASM_TYPE_FUNC) { - wasm::WasmSignature s; s.Kind = s.Other; + // Currently LLVM only models function types, and not other composite + // types. Here we parse the type declarations just enough to skip past + // them in the binary. if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) { uint32_t Supers = readVaruint32(Ctx); if (Supers > 0) { assert(Supers == 1); - uint32_t SuperIndex = readVaruint32(Ctx); + /* Discard SuperIndex */ readVaruint32(Ctx); } Form = readVaruint32(Ctx); llvm::errs() << llvm::format(" Sub Supers %d form %x", Supers, Form) << '\n'; } if (Form == wasm::WASM_TYPE_STRUCT) { - uint32_t NumFields = readVaruint32(Ctx); - for (size_t i = 0; i < NumFields; i++) { + uint32_t FieldCount = readVaruint32(Ctx); + while (FieldCount--) { parseFieldDef(); } - llvm::errs() << llvm::format(" Struct size %d", NumFields) << '\n'; + llvm::errs() << llvm::format(" Struct size %d", FieldCount) << '\n'; } else if (Form == wasm::WASM_TYPE_ARRAY) { parseFieldDef(); llvm::errs() << llvm::format("arr form %x", Form) << '\n'; @@ -1173,10 +1174,9 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { llvm::errs() << llvm::format(" bad form %x", Form) << '\n'; return make_error<GenericBinaryError>("bad form", object_error::parse_failed); } - Signatures.push_back(s); + Sig.Kind = wasm::WasmSignature::Other; + Signatures.push_back(std::move(Sig)); continue; - return make_error<GenericBinaryError>("invalid signature type", - object_error::parse_failed); } uint32_t ParamCount = readVaruint32(Ctx); @@ -1186,7 +1186,6 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { uint32_t ParamType = readUint8(Ctx); Sig.Returns.push_back(parseValType(ParamType)); continue; - } uint32_t ReturnCount = readVaruint32(Ctx); llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount); >From 2b0b6195883979b19d3d029ee56cc69d1957abaf Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Thu, 4 Jan 2024 14:35:20 -0800 Subject: [PATCH 04/12] parses dart global section --- llvm/include/llvm/BinaryFormat/Wasm.h | 9 +++ llvm/lib/Object/WasmObjectFile.cpp | 80 ++++++++++++++++++--------- 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 2cfb69fcf8f8276..a378b20ded75fd7 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -316,6 +316,15 @@ enum : unsigned { WASM_OPCODE_I64_SUB = 0x7d, WASM_OPCODE_I64_MUL = 0x7e, WASM_OPCODE_REF_NULL = 0xd0, + WASM_OPCODE_REF_FUNC = 0xd2, + WASM_OPCODE_GC_PREFIX = 0xfb, +}; + +// Opcodes in the GC-prefixed space (0xfb) +enum : unsigned { + WASM_OPCODE_STRUCT_NEW = 0x00, + WASM_OPCODE_STRUCT_NEW_DEFAULT = 0x01, + WASM_OPCODE_ARRAY_NEW_FIXED = 0x08, }; // Opcodes used in synthetic functions. diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index c7916fdebac85a0..4d33bf82ec43078 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -30,6 +30,7 @@ #include <cassert> #include <cstdint> #include <cstring> +#include <limits> #define DEBUG_TYPE "wasm-object" @@ -174,6 +175,25 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) { return readUint8(Ctx); } +static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, uint32_t Code) { + // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern) + llvm::errs() << llvm::format(" val type %x ", Code); + switch(Code) { + case wasm::WASM_TYPE_I32: + case wasm::WASM_TYPE_I64: + case wasm::WASM_TYPE_F32: + case wasm::WASM_TYPE_F64: + case wasm::WASM_TYPE_V128: + case wasm::WASM_TYPE_FUNCREF: + case wasm::WASM_TYPE_EXTERNREF: + return wasm::ValType(Code); + } + if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { + /* Discard HeapType */ readVarint64(Ctx); + } + return wasm::ValType(wasm::ValType::OTHERREF); +} + static Error readInitExpr(wasm::WasmInitExpr &Expr, WasmObjectFile::ReadContext &Ctx) { auto Start = Ctx.Ptr; @@ -197,10 +217,10 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, Expr.Inst.Value.Global = readULEB128(Ctx); break; case wasm::WASM_OPCODE_REF_NULL: { - wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx)); - if (Ty != wasm::ValType::EXTERNREF) { - return make_error<GenericBinaryError>("invalid type for ref.null", - object_error::parse_failed); + wasm::ValType Ty = parseValType(Ctx, readVaruint32(Ctx)); + if (Ty != wasm::ValType::EXTERNREF) { // maybe something special if the type isn't one we understand? + //return make_error<GenericBinaryError>("invalid type for ref.null", + // object_error::parse_failed); } break; } @@ -218,14 +238,20 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, Ctx.Ptr = Start; while (true) { uint8_t Opcode = readOpcode(Ctx); + llvm::errs() << llvm::format(" opcode %x", Opcode); switch (Opcode) { case wasm::WASM_OPCODE_I32_CONST: case wasm::WASM_OPCODE_GLOBAL_GET: case wasm::WASM_OPCODE_REF_NULL: + case wasm::WASM_OPCODE_REF_FUNC: case wasm::WASM_OPCODE_I64_CONST: + readULEB128(Ctx); + break; case wasm::WASM_OPCODE_F32_CONST: + readFloat32(Ctx); + break; case wasm::WASM_OPCODE_F64_CONST: - readULEB128(Ctx); + readFloat64(Ctx); break; case wasm::WASM_OPCODE_I32_ADD: case wasm::WASM_OPCODE_I32_SUB: @@ -234,8 +260,22 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, case wasm::WASM_OPCODE_I64_SUB: case wasm::WASM_OPCODE_I64_MUL: break; + case wasm::WASM_OPCODE_GC_PREFIX: + break; + // The GC opcodes are in a separate (prefixed space). This flat switch + // structure works as long as there is no overlap between the GC and + // general opcodes used in init exprs. + case wasm::WASM_OPCODE_STRUCT_NEW: + case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT: + readULEB128(Ctx); // heap type index + break; + case wasm::WASM_OPCODE_ARRAY_NEW_FIXED: + readULEB128(Ctx); // heap type index + readULEB128(Ctx); // array size + break; case wasm::WASM_OPCODE_END: Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start); + llvm::errs() << "\n"; return Error::success(); default: return make_error<GenericBinaryError>( @@ -1105,27 +1145,9 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) { } Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { - auto parseValType = [&](uint32_t Code) -> wasm::ValType { - // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern) - llvm::errs() << llvm::format(" val type %x ", Code); - switch(Code) { - case wasm::WASM_TYPE_I32: - case wasm::WASM_TYPE_I64: - case wasm::WASM_TYPE_F32: - case wasm::WASM_TYPE_F64: - case wasm::WASM_TYPE_V128: - case wasm::WASM_TYPE_FUNCREF: - case wasm::WASM_TYPE_EXTERNREF: - return wasm::ValType(Code); - } - if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { - /* Discard HeapType */ readVarint64(Ctx); - } - return wasm::ValType(wasm::ValType::OTHERREF); - }; auto parseFieldDef = [&]() { uint32_t TypeCode = readVaruint32((Ctx)); - /* Discard StorageType */ parseValType(TypeCode); + /* Discard StorageType */ parseValType(Ctx, TypeCode); uint32_t Mutability = readVaruint32(Ctx); llvm::errs() << llvm:: format(" mut %d ", Mutability); }; @@ -1184,14 +1206,14 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { llvm::errs() << llvm::format("param ct %d ", ParamCount); while (ParamCount--) { uint32_t ParamType = readUint8(Ctx); - Sig.Returns.push_back(parseValType(ParamType)); + Sig.Returns.push_back(parseValType(Ctx, ParamType)); continue; } uint32_t ReturnCount = readVaruint32(Ctx); llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount); while (ReturnCount--) { uint32_t ReturnType = readUint8(Ctx); - Sig.Returns.push_back(parseValType(ReturnType)); + Sig.Returns.push_back(parseValType(Ctx, ReturnType)); } Signatures.push_back(std::move(Sig)); @@ -1350,8 +1372,12 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) { while (Count--) { wasm::WasmGlobal Global; Global.Index = NumImportedGlobals + Globals.size(); - Global.Type.Type = readUint8(Ctx); + auto GlobalOpcode = readVaruint32(Ctx); + auto GlobalType = parseValType(Ctx, GlobalOpcode); + //assert(GlobalType <= std::numeric_limits<wasm::ValType>::max()); + Global.Type.Type = (uint8_t)GlobalType; Global.Type.Mutable = readVaruint1(Ctx); + llvm::errs() << llvm::format("Read global %d index %d, type %x mut %d\n", Globals.capacity() -Count-1, Global.Index, GlobalOpcode, Global.Type.Mutable); if (Error Err = readInitExpr(Global.InitExpr, Ctx)) return Err; Globals.push_back(Global); >From 9a524b5431a49e3103230108573d43e8b2df4bd4 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Thu, 4 Jan 2024 14:47:13 -0800 Subject: [PATCH 05/12] fix params --- llvm/lib/Object/WasmObjectFile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 4d33bf82ec43078..13234e0ad2f28f9 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1206,7 +1206,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { llvm::errs() << llvm::format("param ct %d ", ParamCount); while (ParamCount--) { uint32_t ParamType = readUint8(Ctx); - Sig.Returns.push_back(parseValType(Ctx, ParamType)); + Sig.Params.push_back(parseValType(Ctx, ParamType)); continue; } uint32_t ReturnCount = readVaruint32(Ctx); >From 2d3c70fd4c45087943d7040164c2c6a4bb181c7b Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Thu, 4 Jan 2024 15:11:20 -0800 Subject: [PATCH 06/12] add GC opcodes not used by dart sample --- llvm/include/llvm/BinaryFormat/Wasm.h | 4 ++++ llvm/lib/Object/WasmObjectFile.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index a378b20ded75fd7..395f0ab6d2465f0 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -324,7 +324,11 @@ enum : unsigned { enum : unsigned { WASM_OPCODE_STRUCT_NEW = 0x00, WASM_OPCODE_STRUCT_NEW_DEFAULT = 0x01, + WASM_OPCODE_ARRAY_NEW = 0x06, + WASM_OPCODE_ARRAY_NEW_DEFAULT = 0x07, WASM_OPCODE_ARRAY_NEW_FIXED = 0x08, + WASM_OPCODE_REF_I31 = 0x1c, + // any.convert_extern and extern.convert_any don't seem to be supported by Binaryen. }; // Opcodes used in synthetic functions. diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 13234e0ad2f28f9..1bd2b8e75b6ba31 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -267,12 +267,16 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, // general opcodes used in init exprs. case wasm::WASM_OPCODE_STRUCT_NEW: case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT: + case wasm::WASM_OPCODE_ARRAY_NEW: + case wasm::WASM_OPCODE_ARRAY_NEW_DEFAULT: readULEB128(Ctx); // heap type index break; case wasm::WASM_OPCODE_ARRAY_NEW_FIXED: readULEB128(Ctx); // heap type index readULEB128(Ctx); // array size break; + case wasm::WASM_OPCODE_REF_I31: + break; case wasm::WASM_OPCODE_END: Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start); llvm::errs() << "\n"; >From db8bd762f77a7cd3c4ebe45817a89ad9b222c1ad Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Mon, 8 Jan 2024 16:59:47 -0800 Subject: [PATCH 07/12] passes tests, doesn't choke on multi-table.wast --- llvm/include/llvm/BinaryFormat/Wasm.h | 7 ++-- llvm/lib/Object/WasmObjectFile.cpp | 59 ++++++++++++++++++++------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 395f0ab6d2465f0..b48048a38e77f7a 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -81,7 +81,7 @@ struct WasmLimits { }; struct WasmTableType { - uint8_t ElemType; + uint8_t ElemType; // TODO: make this a ValType? WasmLimits Limits; }; @@ -110,7 +110,7 @@ struct WasmInitExpr { }; struct WasmGlobalType { - uint8_t Type; + uint8_t Type; // TODO: make this a ValType? bool Mutable; }; @@ -363,7 +363,8 @@ enum : unsigned { enum : unsigned { WASM_ELEM_SEGMENT_IS_PASSIVE = 0x01, - WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02, + WASM_ELEM_SEGMENT_IS_DECLARATIVE = 0x02, // if passive == 1 + WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02, // if passive == 0 WASM_ELEM_SEGMENT_HAS_INIT_EXPRS = 0x04, }; const unsigned WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND = 0x3; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 1bd2b8e75b6ba31..e3ffea5f8ce20be 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -303,7 +303,8 @@ static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) { static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) { wasm::WasmTableType TableType; - TableType.ElemType = readUint8(Ctx); + auto ElemType = parseValType(Ctx, readVaruint32(Ctx)); + TableType.ElemType = (uint8_t)ElemType; TableType.Limits = readLimits(Ctx); return TableType; } @@ -1617,7 +1618,15 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { return make_error<GenericBinaryError>( "Unsupported flags for element segment", object_error::parse_failed); - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER) + bool IsPassive = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) != 0; + bool IsDeclarative = IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE); + bool HasTableNumber = !IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER); + bool HasInitExprs = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS); + bool HasElemKind = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && !HasInitExprs; + + llvm::errs() << llvm::format("segment %d flags %x, InitExprs %d HasKind %d\n", + ElemSegments.capacity() - Count-1, Segment.Flags, HasInitExprs,HasElemKind); + if (HasTableNumber) Segment.TableNumber = readVaruint32(Ctx); else Segment.TableNumber = 0; @@ -1625,41 +1634,61 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { return make_error<GenericBinaryError>("invalid TableNumber", object_error::parse_failed); - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) { + if (IsDeclarative && false) { + // Declarative segments are not used or understood by LLVM + /* Discard type/kind */ readVaruint32(Ctx); + auto DeclCount = readVaruint32(Ctx); + while(DeclCount--) { + readVaruint32(Ctx); + } + // Dummy element? + + } + if (IsPassive || IsDeclarative) { Segment.Offset.Extended = false; Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST; Segment.Offset.Inst.Value.Int32 = 0; } else { if (Error Err = readInitExpr(Segment.Offset, Ctx)) return Err; + llvm::errs() << llvm::format( " active seg, read initexpr opcode %x\n", Segment.Offset.Inst.Opcode); } - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) { + if (HasElemKind) { 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", + Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF) && + Segment.ElemKind != uint8_t(wasm::ValType::OTHERREF)) { + return make_error<GenericBinaryError>("invalid elem type", object_error::parse_failed); } } else { if (Segment.ElemKind != 0) - return make_error<GenericBinaryError>("invalid elemtype", + return make_error<GenericBinaryError>("invalid elem type", object_error::parse_failed); Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF); } + } else if (HasInitExprs) { + auto ElemType = parseValType(Ctx, readVaruint32(Ctx)); + Segment.ElemKind = uint8_t(ElemType); } else { - Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF); + 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)); + llvm::errs() << llvm::format(" num elems %d\n", NumElems); + + if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) { + while(NumElems--) { + wasm::WasmInitExpr Expr; + if(Error Err = readInitExpr(Expr, Ctx)) + return Err; + } + } else { + while (NumElems--) { + Segment.Functions.push_back(readVaruint32(Ctx)); + } } ElemSegments.push_back(Segment); } >From 04e8a530b40b93ebd2ed3f0f6ed6699435aae2ae Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Fri, 12 Jan 2024 17:17:40 -0800 Subject: [PATCH 08/12] Make TableType a ValType --- lld/wasm/InputFiles.cpp | 2 +- lld/wasm/SymbolTable.cpp | 4 +- llvm/include/llvm/BinaryFormat/Wasm.h | 417 +++++++++--------- llvm/include/llvm/BinaryFormat/WasmTraits.h | 4 +- llvm/include/llvm/MC/MCSymbolWasm.h | 4 +- llvm/lib/MC/WasmObjectWriter.cpp | 4 +- llvm/lib/Object/WasmObjectFile.cpp | 29 +- llvm/lib/ObjectYAML/WasmYAML.cpp | 7 +- .../AsmParser/WebAssemblyAsmParser.cpp | 2 +- .../WebAssembly/WebAssemblyUtilities.cpp | 2 +- llvm/tools/obj2yaml/wasm2yaml.cpp | 4 +- 11 files changed, 244 insertions(+), 235 deletions(-) diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp index 5709a5ced584c72..97c88587231ba93 100644 --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -320,7 +320,7 @@ void ObjFile::addLegacyIndirectFunctionTableIfNeeded( // it has an unexpected name or type, assume that it's not actually the // indirect function table. if (tableImport->Field != functionTableName || - tableImport->Table.ElemType != uint8_t(ValType::FUNCREF)) { + tableImport->Table.ElemType != ValType::FUNCREF) { error(toString(this) + ": table import " + Twine(tableImport->Field) + " is missing a symbol table entry."); return; diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 76370525c371995..b5c138cd76392d2 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -676,7 +676,7 @@ Symbol *SymbolTable::addUndefinedTag(StringRef name, TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) { WasmLimits limits{0, 0, 0}; // Set by the writer. WasmTableType *type = make<WasmTableType>(); - type->ElemType = uint8_t(ValType::FUNCREF); + type->ElemType = ValType::FUNCREF; type->Limits = limits; StringRef module(defaultModule); uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; @@ -690,7 +690,7 @@ TableSymbol *SymbolTable::createUndefinedIndirectFunctionTable(StringRef name) { TableSymbol *SymbolTable::createDefinedIndirectFunctionTable(StringRef name) { const uint32_t invalidIndex = -1; WasmLimits limits{0, 0, 0}; // Set by the writer. - WasmTableType type{uint8_t(ValType::FUNCREF), limits}; + WasmTableType type{ValType::FUNCREF, limits}; WasmTable desc{invalidIndex, type, name}; InputTable *table = make<InputTable>(desc, nullptr); uint32_t flags = config->exportTable ? 0 : WASM_SYMBOL_VISIBILITY_HIDDEN; diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index b48048a38e77f7a..1e7ece3363caa26 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -31,213 +31,6 @@ const uint32_t WasmMetadataVersion = 0x2; // Wasm uses a 64k page size const uint32_t WasmPageSize = 65536; -struct WasmObjectHeader { - StringRef Magic; - uint32_t Version; -}; - -struct WasmDylinkImportInfo { - StringRef Module; - StringRef Field; - uint32_t Flags; -}; - -struct WasmDylinkExportInfo { - StringRef Name; - uint32_t Flags; -}; - -struct WasmDylinkInfo { - uint32_t MemorySize; // Memory size in bytes - uint32_t MemoryAlignment; // P2 alignment of memory - uint32_t TableSize; // Table size in elements - uint32_t TableAlignment; // P2 alignment of table - std::vector<StringRef> Needed; // Shared library dependencies - std::vector<WasmDylinkImportInfo> ImportInfo; - std::vector<WasmDylinkExportInfo> ExportInfo; -}; - -struct WasmProducerInfo { - std::vector<std::pair<std::string, std::string>> Languages; - std::vector<std::pair<std::string, std::string>> Tools; - std::vector<std::pair<std::string, std::string>> SDKs; -}; - -struct WasmFeatureEntry { - uint8_t Prefix; - std::string Name; -}; - -struct WasmExport { - StringRef Name; - uint8_t Kind; - uint32_t Index; -}; - -struct WasmLimits { - uint8_t Flags; - uint64_t Minimum; - uint64_t Maximum; -}; - -struct WasmTableType { - uint8_t ElemType; // TODO: make this a ValType? - WasmLimits Limits; -}; - -struct WasmTable { - uint32_t Index; - WasmTableType Type; - StringRef SymbolName; // from the "linking" section -}; - -struct WasmInitExprMVP { - uint8_t Opcode; - union { - int32_t Int32; - int64_t Int64; - uint32_t Float32; - uint64_t Float64; - uint32_t Global; - } Value; -}; - -struct WasmInitExpr { - uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than - // one instruction) - WasmInitExprMVP Inst; - ArrayRef<uint8_t> Body; -}; - -struct WasmGlobalType { - uint8_t Type; // TODO: make this a ValType? - bool Mutable; -}; - -struct WasmGlobal { - uint32_t Index; - WasmGlobalType Type; - WasmInitExpr InitExpr; - StringRef SymbolName; // from the "linking" section -}; - -struct WasmTag { - uint32_t Index; - uint32_t SigIndex; - StringRef SymbolName; // from the "linking" section -}; - -struct WasmImport { - StringRef Module; - StringRef Field; - uint8_t Kind; - union { - uint32_t SigIndex; - WasmGlobalType Global; - WasmTableType Table; - WasmLimits Memory; - }; -}; - -struct WasmLocalDecl { - uint8_t Type; - uint32_t Count; -}; - -struct WasmFunction { - uint32_t Index; - uint32_t SigIndex; - std::vector<WasmLocalDecl> Locals; - ArrayRef<uint8_t> Body; - uint32_t CodeSectionOffset; - uint32_t Size; - uint32_t CodeOffset; // start of Locals and Body - std::optional<StringRef> ExportName; // from the "export" section - StringRef SymbolName; // from the "linking" section - StringRef DebugName; // from the "name" section - uint32_t Comdat; // from the "comdat info" section -}; - -struct WasmDataSegment { - uint32_t InitFlags; - // Present if InitFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX. - uint32_t MemoryIndex; - // Present if InitFlags & WASM_DATA_SEGMENT_IS_PASSIVE == 0. - WasmInitExpr Offset; - - ArrayRef<uint8_t> Content; - StringRef Name; // from the "segment info" section - uint32_t Alignment; - uint32_t LinkingFlags; - uint32_t Comdat; // from the "comdat info" section -}; - -struct WasmElemSegment { - uint32_t Flags; - uint32_t TableNumber; - uint8_t ElemKind; - WasmInitExpr Offset; - std::vector<uint32_t> Functions; -}; - -// Represents the location of a Wasm data symbol within a WasmDataSegment, as -// the index of the segment, and the offset and size within the segment. -struct WasmDataReference { - uint32_t Segment; - uint64_t Offset; - uint64_t Size; -}; - -struct WasmRelocation { - uint8_t Type; // The type of the relocation. - uint32_t Index; // Index into either symbol or type index space. - uint64_t Offset; // Offset from the start of the section. - int64_t Addend; // A value to add to the symbol. -}; - -struct WasmInitFunc { - uint32_t Priority; - uint32_t Symbol; -}; - -struct WasmSymbolInfo { - StringRef Name; - uint8_t Kind; - uint32_t Flags; - // For undefined symbols the module of the import - std::optional<StringRef> ImportModule; - // For undefined symbols the name of the import - std::optional<StringRef> ImportName; - // For symbols to be exported from the final module - std::optional<StringRef> ExportName; - union { - // For function, table, or global symbols, the index in function, table, or - // global index space. - uint32_t ElementIndex; - // For a data symbols, the address of the data relative to segment. - WasmDataReference DataRef; - }; -}; - -enum class NameType { - FUNCTION, - GLOBAL, - DATA_SEGMENT, -}; - -struct WasmDebugName { - NameType Type; - uint32_t Index; - StringRef Name; -}; - -struct WasmLinkingData { - uint32_t Version; - std::vector<WasmInitFunc> InitFunctions; - std::vector<StringRef> Comdats; - std::vector<WasmSymbolInfo> SymbolTable; -}; - enum : unsigned { WASM_SEC_CUSTOM = 0, // Custom / User-defined section WASM_SEC_TYPE = 1, // Function signature declarations @@ -452,6 +245,11 @@ enum : unsigned { #undef WASM_RELOC +struct WasmObjectHeader { + StringRef Magic; + uint32_t Version; +}; + // Subset of types that a value can have enum class ValType { I32 = WASM_TYPE_I32, @@ -461,7 +259,210 @@ enum class ValType { V128 = WASM_TYPE_V128, FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, - OTHERREF, // Unmodeled value types include ref types with heap types other than funcref or externref + OTHERREF = 0xff, // Unmodeled value types include ref types with heap types other than funcref or externref +}; + +struct WasmDylinkImportInfo { + StringRef Module; + StringRef Field; + uint32_t Flags; +}; + +struct WasmDylinkExportInfo { + StringRef Name; + uint32_t Flags; +}; + +struct WasmDylinkInfo { + uint32_t MemorySize; // Memory size in bytes + uint32_t MemoryAlignment; // P2 alignment of memory + uint32_t TableSize; // Table size in elements + uint32_t TableAlignment; // P2 alignment of table + std::vector<StringRef> Needed; // Shared library dependencies + std::vector<WasmDylinkImportInfo> ImportInfo; + std::vector<WasmDylinkExportInfo> ExportInfo; +}; + +struct WasmProducerInfo { + std::vector<std::pair<std::string, std::string>> Languages; + std::vector<std::pair<std::string, std::string>> Tools; + std::vector<std::pair<std::string, std::string>> SDKs; +}; + +struct WasmFeatureEntry { + uint8_t Prefix; + std::string Name; +}; + +struct WasmExport { + StringRef Name; + uint8_t Kind; + uint32_t Index; +}; + +struct WasmLimits { + uint8_t Flags; + uint64_t Minimum; + uint64_t Maximum; +}; + + +struct WasmTableType { + ValType ElemType; + WasmLimits Limits; +}; + +struct WasmTable { + uint32_t Index; + WasmTableType Type; + StringRef SymbolName; // from the "linking" section +}; + +struct WasmInitExprMVP { + uint8_t Opcode; + union { + int32_t Int32; + int64_t Int64; + uint32_t Float32; + uint64_t Float64; + uint32_t Global; + } Value; +}; + +struct WasmInitExpr { + uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than + // one instruction) + WasmInitExprMVP Inst; + ArrayRef<uint8_t> Body; +}; + +struct WasmGlobalType { + uint8_t Type; // TODO: make this a ValType? + bool Mutable; +}; + +struct WasmGlobal { + uint32_t Index; + WasmGlobalType Type; + WasmInitExpr InitExpr; + StringRef SymbolName; // from the "linking" section +}; + +struct WasmTag { + uint32_t Index; + uint32_t SigIndex; + StringRef SymbolName; // from the "linking" section +}; + +struct WasmImport { + StringRef Module; + StringRef Field; + uint8_t Kind; + union { + uint32_t SigIndex; + WasmGlobalType Global; + WasmTableType Table; + WasmLimits Memory; + }; +}; + +struct WasmLocalDecl { + uint8_t Type; + uint32_t Count; +}; + +struct WasmFunction { + uint32_t Index; + uint32_t SigIndex; + std::vector<WasmLocalDecl> Locals; + ArrayRef<uint8_t> Body; + uint32_t CodeSectionOffset; + uint32_t Size; + uint32_t CodeOffset; // start of Locals and Body + std::optional<StringRef> ExportName; // from the "export" section + StringRef SymbolName; // from the "linking" section + StringRef DebugName; // from the "name" section + uint32_t Comdat; // from the "comdat info" section +}; + +struct WasmDataSegment { + uint32_t InitFlags; + // Present if InitFlags & WASM_DATA_SEGMENT_HAS_MEMINDEX. + uint32_t MemoryIndex; + // Present if InitFlags & WASM_DATA_SEGMENT_IS_PASSIVE == 0. + WasmInitExpr Offset; + + ArrayRef<uint8_t> Content; + StringRef Name; // from the "segment info" section + uint32_t Alignment; + uint32_t LinkingFlags; + uint32_t Comdat; // from the "comdat info" section +}; + +struct WasmElemSegment { + uint32_t Flags; + uint32_t TableNumber; + ValType ElemKind; + WasmInitExpr Offset; + std::vector<uint32_t> Functions; +}; + +// Represents the location of a Wasm data symbol within a WasmDataSegment, as +// the index of the segment, and the offset and size within the segment. +struct WasmDataReference { + uint32_t Segment; + uint64_t Offset; + uint64_t Size; +}; + +struct WasmRelocation { + uint8_t Type; // The type of the relocation. + uint32_t Index; // Index into either symbol or type index space. + uint64_t Offset; // Offset from the start of the section. + int64_t Addend; // A value to add to the symbol. +}; + +struct WasmInitFunc { + uint32_t Priority; + uint32_t Symbol; +}; + +struct WasmSymbolInfo { + StringRef Name; + uint8_t Kind; + uint32_t Flags; + // For undefined symbols the module of the import + std::optional<StringRef> ImportModule; + // For undefined symbols the name of the import + std::optional<StringRef> ImportName; + // For symbols to be exported from the final module + std::optional<StringRef> ExportName; + union { + // For function, table, or global symbols, the index in function, table, or + // global index space. + uint32_t ElementIndex; + // For a data symbols, the address of the data relative to segment. + WasmDataReference DataRef; + }; +}; + +enum class NameType { + FUNCTION, + GLOBAL, + DATA_SEGMENT, +}; + +struct WasmDebugName { + NameType Type; + uint32_t Index; + StringRef Name; +}; + +struct WasmLinkingData { + uint32_t Version; + std::vector<WasmInitFunc> InitFunctions; + std::vector<StringRef> Comdats; + std::vector<WasmSymbolInfo> SymbolTable; }; // Represents anything that can be encoded in the type section, but only diff --git a/llvm/include/llvm/BinaryFormat/WasmTraits.h b/llvm/include/llvm/BinaryFormat/WasmTraits.h index bef9dd3291ca76e..a279ce37a791ed9 100644 --- a/llvm/include/llvm/BinaryFormat/WasmTraits.h +++ b/llvm/include/llvm/BinaryFormat/WasmTraits.h @@ -87,11 +87,11 @@ template <> struct DenseMapInfo<wasm::WasmLimits, void> { template <> struct DenseMapInfo<wasm::WasmTableType, void> { static wasm::WasmTableType getEmptyKey() { return wasm::WasmTableType{ - 0, DenseMapInfo<wasm::WasmLimits, void>::getEmptyKey()}; + wasm::ValType(0), DenseMapInfo<wasm::WasmLimits, void>::getEmptyKey()}; } static wasm::WasmTableType getTombstoneKey() { return wasm::WasmTableType{ - 1, DenseMapInfo<wasm::WasmLimits, void>::getTombstoneKey()}; + wasm::ValType(1), DenseMapInfo<wasm::WasmLimits, void>::getTombstoneKey()}; } static unsigned getHashValue(const wasm::WasmTableType &TableType) { return hash_combine( diff --git a/llvm/include/llvm/MC/MCSymbolWasm.h b/llvm/include/llvm/MC/MCSymbolWasm.h index c67bd64e7cbdfda..0ce95c72a73f702 100644 --- a/llvm/include/llvm/MC/MCSymbolWasm.h +++ b/llvm/include/llvm/MC/MCSymbolWasm.h @@ -112,7 +112,7 @@ class MCSymbolWasm : public MCSymbol { bool isFunctionTable() const { return isTable() && hasTableType() && - getTableType().ElemType == wasm::WASM_TYPE_FUNCREF; + getTableType().ElemType == wasm::ValType::FUNCREF; } void setFunctionTable() { setType(wasm::WASM_SYMBOL_TYPE_TABLE); @@ -144,7 +144,7 @@ class MCSymbolWasm : public MCSymbol { // Declare a table with element type VT and no limits (min size 0, no max // size). wasm::WasmLimits Limits = {wasm::WASM_LIMITS_FLAG_NONE, 0, 0}; - setTableType({uint8_t(VT), Limits}); + setTableType({VT, Limits}); } }; diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index e43f111113b408f..9d8770271163eae 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -972,7 +972,9 @@ void WasmObjectWriter::writeTableSection(ArrayRef<wasm::WasmTable> Tables) { encodeULEB128(Tables.size(), W->OS); for (const wasm::WasmTable &Table : Tables) { - encodeULEB128(Table.Type.ElemType, W->OS); + llvm::errs() << "Table " << Table.Index << std::string(Table.SymbolName) << " type " << (uint32_t)Table.Type.ElemType << "\n"; + assert(Table.Type.ElemType != wasm::ValType::OTHERREF && "Cannot encode general ref-typed tables"); + encodeULEB128((uint32_t)Table.Type.ElemType, W->OS); encodeULEB128(Table.Type.Limits.Flags, W->OS); encodeULEB128(Table.Type.Limits.Minimum, W->OS); if (Table.Type.Limits.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX) diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index e3ffea5f8ce20be..b67b815ed2b72d7 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -304,7 +304,7 @@ static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) { static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) { wasm::WasmTableType TableType; auto ElemType = parseValType(Ctx, readVaruint32(Ctx)); - TableType.ElemType = (uint8_t)ElemType; + TableType.ElemType = ElemType; TableType.Limits = readLimits(Ctx); return TableType; } @@ -1261,8 +1261,9 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) { Im.Table = readTableType(Ctx); NumImportedTables++; auto ElemType = Im.Table.ElemType; - if (ElemType != wasm::WASM_TYPE_FUNCREF && - ElemType != wasm::WASM_TYPE_EXTERNREF) + if (ElemType != wasm::ValType::FUNCREF && + ElemType != wasm::ValType::EXTERNREF && + ElemType != wasm::ValType::OTHERREF) return make_error<GenericBinaryError>("invalid table element type", object_error::parse_failed); break; @@ -1318,8 +1319,9 @@ Error WasmObjectFile::parseTableSection(ReadContext &Ctx) { T.Index = NumImportedTables + Tables.size(); Tables.push_back(T); auto ElemType = Tables.back().Type.ElemType; - if (ElemType != wasm::WASM_TYPE_FUNCREF && - ElemType != wasm::WASM_TYPE_EXTERNREF) { + if (ElemType != wasm::ValType::FUNCREF && + ElemType != wasm::ValType::EXTERNREF && + ElemType != wasm::ValType::OTHERREF) { return make_error<GenericBinaryError>("invalid table element type", object_error::parse_failed); } @@ -1655,25 +1657,26 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { } if (HasElemKind) { - Segment.ElemKind = readUint8(Ctx); + auto ElemKind = readVaruint32(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) && - Segment.ElemKind != uint8_t(wasm::ValType::OTHERREF)) { + Segment.ElemKind = parseValType(Ctx, ElemKind); + if (Segment.ElemKind != wasm::ValType::FUNCREF && + Segment.ElemKind != wasm::ValType::EXTERNREF && + Segment.ElemKind != wasm::ValType::OTHERREF) { return make_error<GenericBinaryError>("invalid elem type", object_error::parse_failed); } } else { - if (Segment.ElemKind != 0) + if (ElemKind != 0) return make_error<GenericBinaryError>("invalid elem type", object_error::parse_failed); - Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF); + Segment.ElemKind = wasm::ValType::FUNCREF; } } else if (HasInitExprs) { auto ElemType = parseValType(Ctx, readVaruint32(Ctx)); - Segment.ElemKind = uint8_t(ElemType); + Segment.ElemKind = ElemType; } else { - Segment.ElemKind = (uint8_t)wasm::ValType::FUNCREF; + Segment.ElemKind = wasm::ValType::FUNCREF; } uint32_t NumElems = readVaruint32(Ctx); diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index 9502fe5e4077881..797902e31ac32ff 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -12,6 +12,7 @@ #include "llvm/ObjectYAML/WasmYAML.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Wasm.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/YAMLTraits.h" @@ -593,7 +594,8 @@ void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration( void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration( IO &IO, WasmYAML::ValueType &Type) { -#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); +#define CONCAT(X) (uint32_t)wasm::ValType::X +#define ECase(X) IO.enumCase(Type, #X, CONCAT(X)); ECase(I32); ECase(I64); ECase(F32); @@ -601,7 +603,8 @@ void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration( ECase(V128); ECase(FUNCREF); ECase(EXTERNREF); - ECase(FUNC); + ECase(OTHERREF); + //ECase(FUNC); #undef ECase } diff --git a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp index 1b92997f03f11c9..3cc4d50271eb114 100644 --- a/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp +++ b/llvm/lib/Target/WebAssembly/AsmParser/WebAssemblyAsmParser.cpp @@ -851,7 +851,7 @@ class WebAssemblyAsmParser final : public MCTargetAsmParser { // symbol auto WasmSym = cast<MCSymbolWasm>(Ctx.getOrCreateSymbol(SymName)); WasmSym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); - wasm::WasmTableType Type = {uint8_t(*ElemType), Limits}; + wasm::WasmTableType Type = {*ElemType, Limits}; WasmSym->setTableType(Type); TOut.emitTableType(WasmSym); return expect(AsmToken::EndOfStatement, "EOL"); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index 189111cef7d0a04..ac7cf5b37fcaa49 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -134,7 +134,7 @@ MCSymbolWasm *WebAssembly::getOrCreateFuncrefCallTableSymbol( Sym->setWeak(true); wasm::WasmLimits Limits = {0, 1, 1}; - wasm::WasmTableType TableType = {wasm::WASM_TYPE_FUNCREF, Limits}; + wasm::WasmTableType TableType = {wasm::ValType::FUNCREF, Limits}; Sym->setType(wasm::WASM_SYMBOL_TYPE_TABLE); Sym->setTableType(TableType); } diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp index 8557a38405193bb..c15d64cef8d65e4 100644 --- a/llvm/tools/obj2yaml/wasm2yaml.cpp +++ b/llvm/tools/obj2yaml/wasm2yaml.cpp @@ -44,7 +44,7 @@ static WasmYAML::Table makeTable(uint32_t Index, const wasm::WasmTableType &Type) { WasmYAML::Table T; T.Index = Index; - T.ElemType = Type.ElemType; + T.ElemType = (uint32_t)Type.ElemType; T.TableLimits = makeLimits(Type.Limits); return T; } @@ -334,7 +334,7 @@ ErrorOr<WasmYAML::Object *> WasmDumper::dump() { WasmYAML::ElemSegment Seg; Seg.Flags = Segment.Flags; Seg.TableNumber = Segment.TableNumber; - Seg.ElemKind = Segment.ElemKind; + Seg.ElemKind = (uint32_t)Segment.ElemKind; Seg.Offset.Extended = Segment.Offset.Extended; if (Seg.Offset.Extended) { Seg.Offset.Body = yaml::BinaryRef(Segment.Offset.Body); >From 64e0ae785149714ac848833dc4af34ab28e95ef9 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Fri, 19 Jan 2024 16:11:01 -0800 Subject: [PATCH 09/12] obj2yaml dumps elemkind --- lld/wasm/WriterUtils.cpp | 2 + llvm/include/llvm/BinaryFormat/Wasm.h | 4 +- llvm/lib/Object/WasmObjectFile.cpp | 7 +- llvm/lib/ObjectYAML/WasmYAML.cpp | 5 +- .../WebAssembly/WebAssemblyAsmPrinter.cpp | 3 +- llvm/test/Object/Inputs/WASM/multi-table.wasm | Bin 0 -> 185 bytes llvm/test/Object/wasm-obj2yaml-tables.test | 112 ++++++++++++++++++ 7 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 llvm/test/Object/Inputs/WASM/multi-table.wasm create mode 100644 llvm/test/Object/wasm-obj2yaml-tables.test diff --git a/lld/wasm/WriterUtils.cpp b/lld/wasm/WriterUtils.cpp index cc8ed0b1de23712..02c8dd677f635aa 100644 --- a/lld/wasm/WriterUtils.cpp +++ b/lld/wasm/WriterUtils.cpp @@ -35,6 +35,8 @@ std::string toString(ValType type) { return "funcref"; case ValType::EXTERNREF: return "externref"; + case ValType::OTHERREF: + return "otherref"; } llvm_unreachable("Invalid wasm::ValType"); } diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 9dbed31c21ffffd..2bcd87039ceb00f 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -259,7 +259,9 @@ enum class ValType { V128 = WASM_TYPE_V128, FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, - OTHERREF = 0xff, // Unmodeled value types include ref types with heap types other than funcref or externref + // Unmodeled value types include ref types with heap types other than + // funcr or extern, and type-specialized funcrefs + OTHERREF = 0xff, }; struct WasmDylinkImportInfo { diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index b67b815ed2b72d7..6edab3e0502d132 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1626,10 +1626,11 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { bool HasInitExprs = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS); bool HasElemKind = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && !HasInitExprs; - llvm::errs() << llvm::format("segment %d flags %x, InitExprs %d HasKind %d\n", + llvm::errs() << llvm::format("\nsegment %d flags %x, InitExprs %d HasKind %d\n", ElemSegments.capacity() - Count-1, Segment.Flags, HasInitExprs,HasElemKind); - if (HasTableNumber) + if (HasTableNumber) { Segment.TableNumber = readVaruint32(Ctx); + llvm::errs() << " table " << Segment.TableNumber << "\n"; } else Segment.TableNumber = 0; if (!isValidTableNumber(Segment.TableNumber)) @@ -1682,7 +1683,7 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { uint32_t NumElems = readVaruint32(Ctx); llvm::errs() << llvm::format(" num elems %d\n", NumElems); - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) { + if (HasInitExprs) { while(NumElems--) { wasm::WasmInitExpr Expr; if(Error Err = readInitExpr(Expr, Ctx)) diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index 797902e31ac32ff..908778daa0304eb 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -384,6 +384,7 @@ void MappingTraits<WasmYAML::ElemSegment>::mapping( if (!IO.outputting() || Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) IO.mapOptional("ElemKind", Segment.ElemKind); + // TODO: Omit "offset" for passive segments? It's neither meaningful nor encoded. IO.mapRequired("Offset", Segment.Offset); IO.mapRequired("Functions", Segment.Functions); } @@ -634,9 +635,11 @@ void ScalarEnumerationTraits<WasmYAML::Opcode>::enumeration( void ScalarEnumerationTraits<WasmYAML::TableType>::enumeration( IO &IO, WasmYAML::TableType &Type) { -#define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); +#define CONCAT(X) (uint32_t)wasm::ValType::X +#define ECase(X) IO.enumCase(Type, #X, CONCAT(X)); ECase(FUNCREF); ECase(EXTERNREF); + ECase(OTHERREF); #undef ECase } diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 908efbb8d32155d..fb949d4b19a3e12 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -125,8 +125,9 @@ static char getInvokeSig(wasm::ValType VT) { return 'F'; case wasm::ValType::EXTERNREF: return 'X'; + default: + llvm_unreachable("Unhandled wasm::ValType enum"); } - llvm_unreachable("Unhandled wasm::ValType enum"); } // Given the wasm signature, generate the invoke name in the format JS glue code diff --git a/llvm/test/Object/Inputs/WASM/multi-table.wasm b/llvm/test/Object/Inputs/WASM/multi-table.wasm new file mode 100644 index 0000000000000000000000000000000000000000..47f5d8311cb74f76485577df85578b62f896361d GIT binary patch literal 185 zcmX|(K@P$&3<P&=ClWCd;>xuz=}#z8j}?*n0KSOwBAkLaSfjDmi)G&kfW|u@g<SYx zBa52G-mccD+GzF!Dwt9}O9eXog&BTY%K#w^;2<3WW|`<sBKY1t%Pd|otaGHJsp;3^ ZoGR=u)2KtX==*($my0HJxw(SJd;l027?A(~ literal 0 HcmV?d00001 diff --git a/llvm/test/Object/wasm-obj2yaml-tables.test b/llvm/test/Object/wasm-obj2yaml-tables.test new file mode 100644 index 000000000000000..870ffd179a1c25b --- /dev/null +++ b/llvm/test/Object/wasm-obj2yaml-tables.test @@ -0,0 +1,112 @@ +RUN: obj2yaml %p/Inputs/WASM/multi-table.wasm | FileCheck %s + + +# CHECK: - Type: TABLE +# CHECK: Tables: +# CHECK: - Index: 1 +# CHECK: ElemType: FUNCREF +# CHECK: Limits: +# CHECK: Flags: [ HAS_MAX ] +# CHECK: Minimum: 0x3 +# CHECK: Maximum: 0x3 +# CHECK: - Index: 2 +# CHECK: ElemType: FUNCREF +# CHECK: Limits: +# CHECK: Flags: [ HAS_MAX ] +# CHECK: Minimum: 0x4 +# CHECK: Maximum: 0x4 +# CHECK: - Index: 3 +# CHECK: ElemType: EXTERNREF +# CHECK: Limits: +# CHECK: Minimum: 0x0 +# CHECK: - Index: 4 +# CHECK: ElemType: OTHERREF +# CHECK: Limits: +# CHECK: Flags: [ HAS_MAX ] +# CHECK: Minimum: 0x5 +# CHECK: Maximum: 0x5 +# CHECK: - Type: GLOBAL +# CHECK: Globals: +# CHECK: - Index: 0 +# CHECK: Type: OTHERREF +# CHECK: Mutable: false +# CHECK: InitExpr: +# CHECK: Extended: true +# CHECK: Body: D2000B +# CHECK: - Index: 1 +# CHECK: Type: I32 +# CHECK: Mutable: false +# CHECK: InitExpr: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# CHECK: - Type: ELEM +# CHECK: Segments: +# CHECK: - Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# CHECK: Functions: [ 0 ] +# CHECK: - Flags: 2 +# CHECK: TableNumber: 1 +# CHECK: ElemKind: FUNCREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# CHECK: Functions: [ 0 ] +# CHECK: - Flags: 2 +# CHECK: TableNumber: 1 +# CHECK: ElemKind: FUNCREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 1 +# CHECK: Functions: [ 0, 1 ] +# CHECK: - Flags: 6 +# CHECK: TableNumber: 2 +# CHECK: ElemKind: FUNCREF +# CHECK: Offset: +# CHECK: Opcode: GLOBAL_GET +# CHECK: Index: 1 +# There are 2 funcions encoded with initexprs in this segment +# but initexprs in tables are unmodeled. +# CHECK: Functions: [ ] +# CHECK: - Flags: 6 +# CHECK: TableNumber: 2 +# This elemkind is OTHERREF because it's encoded as a typed funcref +# CHECK: ElemKind: OTHERREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 2 +# CHECK: Functions: [ ] +# CHECK: - Flags: 1 +# CHECK: ElemKind: FUNCREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# CHECK: Functions: [ 0, 1 ] +# CHECK: - Flags: 5 +# CHECK: ElemKind: FUNCREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# Empty function list, encoded with initexprs +# CHECK: Functions: [ ] +# CHECK: - Flags: 5 +# CHECK: ElemKind: OTHERREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# Function list encoded with initexprs +# CHECK: Functions: [ ] +# CHECK: - Flags: 1 +# CHECK: ElemKind: FUNCREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# CHECK: Functions: [ ] +# CHECK: - Flags: 6 +# CHECK: TableNumber: 4 +# CHECK: ElemKind: OTHERREF +# CHECK: Offset: +# CHECK: Opcode: I32_CONST +# CHECK: Value: 0 +# Function list encoded with initexprs +# CHECK: Functions: [ ] >From 8d0e4528e2d3fdbed1e951e41a728d62b93513b9 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Tue, 23 Jan 2024 16:36:30 -0800 Subject: [PATCH 10/12] update signature kinds, clang-format --- lld/wasm/InputChunks.h | 5 ++++- lld/wasm/InputElement.h | 4 +++- llvm/include/llvm/BinaryFormat/Wasm.h | 12 +++++++++--- llvm/include/llvm/Object/Wasm.h | 4 +++- llvm/lib/Object/WasmObjectFile.cpp | 13 +++++++++---- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/lld/wasm/InputChunks.h b/lld/wasm/InputChunks.h index 1e430832fb84c72..ad1d45e335eac90 100644 --- a/lld/wasm/InputChunks.h +++ b/lld/wasm/InputChunks.h @@ -259,10 +259,13 @@ class InputFunction : public InputChunk { file->codeSection->Content.slice(inputSectionOffset, function->Size); debugName = function->DebugName; comdat = function->Comdat; + assert(s.Kind != WasmSignature::Placeholder); } InputFunction(StringRef name, const WasmSignature &s) - : InputChunk(nullptr, InputChunk::Function, name), signature(s) {} + : InputChunk(nullptr, InputChunk::Function, name), signature(s) { + assert(s.Kind == WasmSignature::Function); + } static bool classof(const InputChunk *c) { return c->kind() == InputChunk::Function || diff --git a/lld/wasm/InputElement.h b/lld/wasm/InputElement.h index 46e21d7c7dfd800..10dc2a3e4a826a9 100644 --- a/lld/wasm/InputElement.h +++ b/lld/wasm/InputElement.h @@ -76,7 +76,9 @@ class InputGlobal : public InputElement { class InputTag : public InputElement { public: InputTag(const WasmSignature &s, const WasmTag &t, ObjFile *f) - : InputElement(t.SymbolName, f), signature(s) {} + : InputElement(t.SymbolName, f), signature(s) { + assert(s.Kind == WasmSignature::Tag); + } const WasmSignature &signature; }; diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 2bcd87039ceb00f..9f13cf4e36a855e 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -400,6 +400,11 @@ struct WasmDataSegment { uint32_t Comdat; // from the "comdat info" section }; +// Represents a Wasm element segment, with some limitations compared the spec: +// 1) Does not model passive or declarative segments (Segment will end up with +// an Offset field of i32.const 0) +// 2) Does not model init exprs (Segment will get an empty Functions list) +// 2) Does not model types other than basic funcref/externref (see ValType) struct WasmElemSegment { uint32_t Flags; uint32_t TableNumber; @@ -466,12 +471,13 @@ struct WasmLinkingData { std::vector<WasmSymbolInfo> SymbolTable; }; -// Represents anything that can be encoded in the type section, but only -// signatures are actually modeled. TODO: maybe refactor to make this explicit. struct WasmSignature { SmallVector<ValType, 1> Returns; SmallVector<ValType, 4> Params; - enum {Function, Other} Kind = Function; // Recursive, Composite(Array,Struct), + // LLVM can parse types other than functions encoded in the type section, + // but does not actually model them. Instead a placeholder signature is + // created in the Object's signature list. + enum { Function, Tag, Placeholder } Kind = Function; // Support empty and tombstone instances, needed by DenseMap. enum { Plain, Empty, Tombstone } State = Plain; diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h index 6b8edb90e144b58..737a6eb9355c64b 100644 --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -39,7 +39,9 @@ class WasmSymbol { const wasm::WasmTableType *TableType, const wasm::WasmSignature *Signature) : Info(Info), GlobalType(GlobalType), TableType(TableType), - Signature(Signature) {} + Signature(Signature) { + assert(!Signature || Signature->Kind != wasm::WasmSignature::Placeholder); + } const wasm::WasmSymbolInfo &Info; const wasm::WasmGlobalType *GlobalType; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 6edab3e0502d132..48e351f34057204 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1167,11 +1167,13 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { // Rec groups expand the type index space (beyond what was declared at // the top of the section, and also consume one element in that space. uint32_t RecSize = readVaruint32(Ctx); - assert(RecSize > 0); // TODO real errors here and below + if (RecSize == 0) + return make_error<GenericBinaryError>("Rec group size cannot be 0", + object_error::parse_failed); Signatures.reserve(Signatures.size() + RecSize); Count += RecSize; llvm::errs() << llvm::format(" Rec size %d\n", RecSize); - Sig.Kind = wasm::WasmSignature::Other; + Sig.Kind = wasm::WasmSignature::Placeholder; Signatures.push_back(std::move(Sig)); continue; } @@ -1182,7 +1184,9 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) { uint32_t Supers = readVaruint32(Ctx); if (Supers > 0) { - assert(Supers == 1); + if (Supers != 1) + return make_error<GenericBinaryError>( + "Invalid number of supertypes", object_error::parse_failed); /* Discard SuperIndex */ readVaruint32(Ctx); } Form = readVaruint32(Ctx); @@ -1201,7 +1205,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { llvm::errs() << llvm::format(" bad form %x", Form) << '\n'; return make_error<GenericBinaryError>("bad form", object_error::parse_failed); } - Sig.Kind = wasm::WasmSignature::Other; + Sig.Kind = wasm::WasmSignature::Placeholder; Signatures.push_back(std::move(Sig)); continue; } @@ -1363,6 +1367,7 @@ Error WasmObjectFile::parseTagSection(ReadContext &Ctx) { wasm::WasmTag Tag; Tag.Index = NumImportedTags + Tags.size(); Tag.SigIndex = Type; + Signatures[Type].Kind = wasm::WasmSignature::Tag; Tags.push_back(Tag); } >From 1cb58ca7602fc604f0d146fcc06fe5abeca6c240 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Tue, 23 Jan 2024 17:02:57 -0800 Subject: [PATCH 11/12] clean up, remove printfs, clang-format --- llvm/include/llvm/BinaryFormat/Wasm.h | 11 ++- llvm/lib/MC/WasmObjectWriter.cpp | 4 +- llvm/lib/Object/WasmObjectFile.cpp | 101 ++++++++++---------------- llvm/lib/ObjectYAML/WasmYAML.cpp | 8 +- 4 files changed, 52 insertions(+), 72 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index 9f13cf4e36a855e..cd13b7014bfe265 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -70,7 +70,7 @@ enum : unsigned { WASM_TYPE_NONNULLABLE = 0x64, WASM_TYPE_NULLABLE = 0x63, WASM_TYPE_FUNC = 0x60, - WASM_TYPE_ARRAY = 0x5E, // Composite types, not used for codegen + WASM_TYPE_ARRAY = 0x5E, WASM_TYPE_STRUCT = 0x5F, WASM_TYPE_SUB = 0x50, WASM_TYPE_SUB_FINAL = 0x4F, @@ -121,7 +121,8 @@ enum : unsigned { WASM_OPCODE_ARRAY_NEW_DEFAULT = 0x07, WASM_OPCODE_ARRAY_NEW_FIXED = 0x08, WASM_OPCODE_REF_I31 = 0x1c, - // any.convert_extern and extern.convert_any don't seem to be supported by Binaryen. + // any.convert_extern and extern.convert_any don't seem to be supported by + // Binaryen. }; // Opcodes used in synthetic functions. @@ -156,7 +157,7 @@ enum : unsigned { enum : unsigned { WASM_ELEM_SEGMENT_IS_PASSIVE = 0x01, - WASM_ELEM_SEGMENT_IS_DECLARATIVE = 0x02, // if passive == 1 + WASM_ELEM_SEGMENT_IS_DECLARATIVE = 0x02, // if passive == 1 WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER = 0x02, // if passive == 0 WASM_ELEM_SEGMENT_HAS_INIT_EXPRS = 0x04, }; @@ -260,7 +261,7 @@ enum class ValType { FUNCREF = WASM_TYPE_FUNCREF, EXTERNREF = WASM_TYPE_EXTERNREF, // Unmodeled value types include ref types with heap types other than - // funcr or extern, and type-specialized funcrefs + // func or extern, and type-specialized funcrefs OTHERREF = 0xff, }; @@ -330,6 +331,8 @@ struct WasmInitExprMVP { } Value; }; +// Extended-const init exprs and exprs with GC types are not explicitly +// modeled, but the raw body of the expr is attached. struct WasmInitExpr { uint8_t Extended; // Set to non-zero if extended const is used (i.e. more than // one instruction) diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index 9d8770271163eae..985f9351f4a3085 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -972,8 +972,8 @@ void WasmObjectWriter::writeTableSection(ArrayRef<wasm::WasmTable> Tables) { encodeULEB128(Tables.size(), W->OS); for (const wasm::WasmTable &Table : Tables) { - llvm::errs() << "Table " << Table.Index << std::string(Table.SymbolName) << " type " << (uint32_t)Table.Type.ElemType << "\n"; - assert(Table.Type.ElemType != wasm::ValType::OTHERREF && "Cannot encode general ref-typed tables"); + assert(Table.Type.ElemType != wasm::ValType::OTHERREF && + "Cannot encode general ref-typed tables"); encodeULEB128((uint32_t)Table.Type.ElemType, W->OS); encodeULEB128(Table.Type.Limits.Flags, W->OS); encodeULEB128(Table.Type.Limits.Minimum, W->OS); diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 48e351f34057204..e7006473449bc7a 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -175,23 +175,24 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) { return readUint8(Ctx); } -static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, uint32_t Code) { - // only directly encoded FUNCREF/EXTERNREF are supported (not ref null func/ref null extern) - llvm::errs() << llvm::format(" val type %x ", Code); - switch(Code) { - case wasm::WASM_TYPE_I32: - case wasm::WASM_TYPE_I64: - case wasm::WASM_TYPE_F32: - case wasm::WASM_TYPE_F64: - case wasm::WASM_TYPE_V128: - case wasm::WASM_TYPE_FUNCREF: - case wasm::WASM_TYPE_EXTERNREF: - return wasm::ValType(Code); - } - if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { - /* Discard HeapType */ readVarint64(Ctx); - } - return wasm::ValType(wasm::ValType::OTHERREF); +static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, + uint32_t Code) { + // only directly encoded FUNCREF/EXTERNREF are supported + // (not ref null func or ref null extern) + switch (Code) { + case wasm::WASM_TYPE_I32: + case wasm::WASM_TYPE_I64: + case wasm::WASM_TYPE_F32: + case wasm::WASM_TYPE_F64: + case wasm::WASM_TYPE_V128: + case wasm::WASM_TYPE_FUNCREF: + case wasm::WASM_TYPE_EXTERNREF: + return wasm::ValType(Code); + } + if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { + /* Discard HeapType */ readVarint64(Ctx); + } + return wasm::ValType(wasm::ValType::OTHERREF); } static Error readInitExpr(wasm::WasmInitExpr &Expr, @@ -217,11 +218,7 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, Expr.Inst.Value.Global = readULEB128(Ctx); break; case wasm::WASM_OPCODE_REF_NULL: { - wasm::ValType Ty = parseValType(Ctx, readVaruint32(Ctx)); - if (Ty != wasm::ValType::EXTERNREF) { // maybe something special if the type isn't one we understand? - //return make_error<GenericBinaryError>("invalid type for ref.null", - // object_error::parse_failed); - } + /* Discard type */ parseValType(Ctx, readVaruint32(Ctx)); break; } default: @@ -238,7 +235,6 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, Ctx.Ptr = Start; while (true) { uint8_t Opcode = readOpcode(Ctx); - llvm::errs() << llvm::format(" opcode %x", Opcode); switch (Opcode) { case wasm::WASM_OPCODE_I32_CONST: case wasm::WASM_OPCODE_GLOBAL_GET: @@ -279,7 +275,6 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, break; case wasm::WASM_OPCODE_END: Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start); - llvm::errs() << "\n"; return Error::success(); default: return make_error<GenericBinaryError>( @@ -1153,8 +1148,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { auto parseFieldDef = [&]() { uint32_t TypeCode = readVaruint32((Ctx)); /* Discard StorageType */ parseValType(Ctx, TypeCode); - uint32_t Mutability = readVaruint32(Ctx); - llvm::errs() << llvm:: format(" mut %d ", Mutability); + /* Discard Mutability */ readVaruint32(Ctx); }; uint32_t Count = readVaruint32(Ctx); @@ -1162,7 +1156,6 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { while (Count--) { wasm::WasmSignature Sig; uint8_t Form = readUint8(Ctx); - llvm::errs() << llvm::format("Top Count %d form %x", Count, Form) << '\n'; if (Form == wasm::WASM_TYPE_REC) { // Rec groups expand the type index space (beyond what was declared at // the top of the section, and also consume one element in that space. @@ -1172,7 +1165,6 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { object_error::parse_failed); Signatures.reserve(Signatures.size() + RecSize); Count += RecSize; - llvm::errs() << llvm::format(" Rec size %d\n", RecSize); Sig.Kind = wasm::WasmSignature::Placeholder; Signatures.push_back(std::move(Sig)); continue; @@ -1190,20 +1182,17 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { /* Discard SuperIndex */ readVaruint32(Ctx); } Form = readVaruint32(Ctx); - llvm::errs() << llvm::format(" Sub Supers %d form %x", Supers, Form) << '\n'; } if (Form == wasm::WASM_TYPE_STRUCT) { uint32_t FieldCount = readVaruint32(Ctx); while (FieldCount--) { parseFieldDef(); } - llvm::errs() << llvm::format(" Struct size %d", FieldCount) << '\n'; } else if (Form == wasm::WASM_TYPE_ARRAY) { parseFieldDef(); - llvm::errs() << llvm::format("arr form %x", Form) << '\n'; } else { - llvm::errs() << llvm::format(" bad form %x", Form) << '\n'; - return make_error<GenericBinaryError>("bad form", object_error::parse_failed); + return make_error<GenericBinaryError>("bad form", + object_error::parse_failed); } Sig.Kind = wasm::WasmSignature::Placeholder; Signatures.push_back(std::move(Sig)); @@ -1212,21 +1201,18 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { uint32_t ParamCount = readVaruint32(Ctx); Sig.Params.reserve(ParamCount); - llvm::errs() << llvm::format("param ct %d ", ParamCount); while (ParamCount--) { uint32_t ParamType = readUint8(Ctx); Sig.Params.push_back(parseValType(Ctx, ParamType)); continue; } uint32_t ReturnCount = readVaruint32(Ctx); - llvm::errs() << llvm::format("\nreturn ct %d ", ReturnCount); while (ReturnCount--) { uint32_t ReturnType = readUint8(Ctx); Sig.Returns.push_back(parseValType(Ctx, ReturnType)); } - + Signatures.push_back(std::move(Sig)); - llvm::errs() << '\n'; } if (Ctx.Ptr != Ctx.End) return make_error<GenericBinaryError>("type section ended prematurely", @@ -1386,10 +1372,9 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) { Global.Index = NumImportedGlobals + Globals.size(); auto GlobalOpcode = readVaruint32(Ctx); auto GlobalType = parseValType(Ctx, GlobalOpcode); - //assert(GlobalType <= std::numeric_limits<wasm::ValType>::max()); + // assert(GlobalType <= std::numeric_limits<wasm::ValType>::max()); Global.Type.Type = (uint8_t)GlobalType; Global.Type.Mutable = readVaruint1(Ctx); - llvm::errs() << llvm::format("Read global %d index %d, type %x mut %d\n", Globals.capacity() -Count-1, Global.Index, GlobalOpcode, Global.Type.Mutable); if (Error Err = readInitExpr(Global.InitExpr, Ctx)) return Err; Globals.push_back(Global); @@ -1626,32 +1611,26 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { "Unsupported flags for element segment", object_error::parse_failed); bool IsPassive = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) != 0; - bool IsDeclarative = IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE); - bool HasTableNumber = !IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER); - bool HasInitExprs = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS); - bool HasElemKind = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && !HasInitExprs; - - llvm::errs() << llvm::format("\nsegment %d flags %x, InitExprs %d HasKind %d\n", - ElemSegments.capacity() - Count-1, Segment.Flags, HasInitExprs,HasElemKind); - if (HasTableNumber) { + bool IsDeclarative = + IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE); + bool HasTableNumber = + !IsPassive && + (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER); + bool HasInitExprs = + (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS); + bool HasElemKind = + (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && + !HasInitExprs; + + if (HasTableNumber) Segment.TableNumber = readVaruint32(Ctx); - llvm::errs() << " table " << Segment.TableNumber << "\n"; } else Segment.TableNumber = 0; + if (!isValidTableNumber(Segment.TableNumber)) return make_error<GenericBinaryError>("invalid TableNumber", object_error::parse_failed); - if (IsDeclarative && false) { - // Declarative segments are not used or understood by LLVM - /* Discard type/kind */ readVaruint32(Ctx); - auto DeclCount = readVaruint32(Ctx); - while(DeclCount--) { - readVaruint32(Ctx); - } - // Dummy element? - - } if (IsPassive || IsDeclarative) { Segment.Offset.Extended = false; Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST; @@ -1659,7 +1638,6 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { } else { if (Error Err = readInitExpr(Segment.Offset, Ctx)) return Err; - llvm::errs() << llvm::format( " active seg, read initexpr opcode %x\n", Segment.Offset.Inst.Opcode); } if (HasElemKind) { @@ -1686,12 +1664,11 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { } uint32_t NumElems = readVaruint32(Ctx); - llvm::errs() << llvm::format(" num elems %d\n", NumElems); if (HasInitExprs) { - while(NumElems--) { + while (NumElems--) { wasm::WasmInitExpr Expr; - if(Error Err = readInitExpr(Expr, Ctx)) + if (Error Err = readInitExpr(Expr, Ctx)) return Err; } } else { diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index 908778daa0304eb..3b53788eddbabcc 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -384,7 +384,8 @@ void MappingTraits<WasmYAML::ElemSegment>::mapping( if (!IO.outputting() || Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) IO.mapOptional("ElemKind", Segment.ElemKind); - // TODO: Omit "offset" for passive segments? It's neither meaningful nor encoded. + // TODO: Omit "offset" for passive segments? It's neither meaningful nor + // encoded. IO.mapRequired("Offset", Segment.Offset); IO.mapRequired("Functions", Segment.Functions); } @@ -595,7 +596,7 @@ void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration( void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration( IO &IO, WasmYAML::ValueType &Type) { -#define CONCAT(X) (uint32_t)wasm::ValType::X +#define CONCAT(X) (uint32_t) wasm::ValType::X #define ECase(X) IO.enumCase(Type, #X, CONCAT(X)); ECase(I32); ECase(I64); @@ -605,7 +606,6 @@ void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration( ECase(FUNCREF); ECase(EXTERNREF); ECase(OTHERREF); - //ECase(FUNC); #undef ECase } @@ -635,7 +635,7 @@ void ScalarEnumerationTraits<WasmYAML::Opcode>::enumeration( void ScalarEnumerationTraits<WasmYAML::TableType>::enumeration( IO &IO, WasmYAML::TableType &Type) { -#define CONCAT(X) (uint32_t)wasm::ValType::X +#define CONCAT(X) (uint32_t) wasm::ValType::X #define ECase(X) IO.enumCase(Type, #X, CONCAT(X)); ECase(FUNCREF); ECase(EXTERNREF); >From 1326cf3dc711acd40179902310660b265cfe25d2 Mon Sep 17 00:00:00 2001 From: Derek Schuff <dsch...@chromium.org> Date: Wed, 24 Jan 2024 17:32:20 -0800 Subject: [PATCH 12/12] Check linker inputs for unmodeled types --- lld/wasm/InputFiles.cpp | 3 +++ llvm/include/llvm/Object/Wasm.h | 2 ++ llvm/lib/Object/WasmObjectFile.cpp | 2 ++ 3 files changed, 7 insertions(+) diff --git a/lld/wasm/InputFiles.cpp b/lld/wasm/InputFiles.cpp index f5e946aca8b2a8f..f43c39b218787c3 100644 --- a/lld/wasm/InputFiles.cpp +++ b/lld/wasm/InputFiles.cpp @@ -81,6 +81,9 @@ InputFile *createObjectFile(MemoryBufferRef mb, StringRef archiveName, std::unique_ptr<Binary> bin = CHECK(createBinary(mb), mb.getBufferIdentifier()); auto *obj = cast<WasmObjectFile>(bin.get()); + if (obj->hasUnmodeledTypes()) + fatal(toString(mb.getBufferIdentifier()) + + "file has unmodeled reference or GC types"); if (obj->isSharedObject()) return make<SharedFile>(mb); return make<ObjFile>(mb, archiveName, lazy); diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h index 737a6eb9355c64b..927dce882f6ae55 100644 --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -211,6 +211,7 @@ class WasmObjectFile : public ObjectFile { Expected<SubtargetFeatures> getFeatures() const override; bool isRelocatableObject() const override; bool isSharedObject() const; + bool hasUnmodeledTypes() const { return HasUnmodeledTypes; } struct ReadContext { const uint8_t *Start; @@ -293,6 +294,7 @@ class WasmObjectFile : public ObjectFile { bool HasLinkingSection = false; bool HasDylinkSection = false; bool HasMemory64 = false; + bool HasUnmodeledTypes = false; wasm::WasmLinkingData LinkingData; uint32_t NumImportedGlobals = 0; uint32_t NumImportedTables = 0; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index e7006473449bc7a..953e7c70b5f6e31 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -1167,6 +1167,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { Count += RecSize; Sig.Kind = wasm::WasmSignature::Placeholder; Signatures.push_back(std::move(Sig)); + HasUnmodeledTypes = true; continue; } if (Form != wasm::WASM_TYPE_FUNC) { @@ -1196,6 +1197,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { } Sig.Kind = wasm::WasmSignature::Placeholder; Signatures.push_back(std::move(Sig)); + HasUnmodeledTypes = true; continue; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits