[llvm] [lld] [clang] [clang-tools-extra] [Object][Wasm] Allow parsing of GC types in type and table sections (PR #79235)
Derek Schuff via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 24 17:32:43 PST 2024
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 <dschuff at 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 <dschuff at 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 <dschuff at 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 <dschuff at 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 <dschuff at 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 <dschuff at 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 <dschuff at 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 <dschuff at 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 <dschuff at 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 at P$&3<P&=ClWCd;>xuz=}#z8j}?*n0KSOwBAkLaSfjDmi)G&kfW|u at 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 <dschuff at 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 <dschuff at 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 <dschuff at 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;
}
More information about the cfe-commits
mailing list