aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object/WasmObjectFile.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Object/WasmObjectFile.cpp')
-rw-r--r--llvm/lib/Object/WasmObjectFile.cpp173
1 files changed, 145 insertions, 28 deletions
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index b9a8e97..953e7c7 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 <limits>
#define DEBUG_TYPE "wasm-object"
@@ -173,6 +175,26 @@ 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 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,
WasmObjectFile::ReadContext &Ctx) {
auto Start = Ctx.Ptr;
@@ -196,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 = static_cast<wasm::ValType>(readULEB128(Ctx));
- if (Ty != wasm::ValType::EXTERNREF) {
- return make_error<GenericBinaryError>("invalid type for ref.null",
- object_error::parse_failed);
- }
+ /* Discard type */ parseValType(Ctx, readVaruint32(Ctx));
break;
}
default:
@@ -221,10 +239,15 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr,
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:
@@ -233,6 +256,23 @@ 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:
+ 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);
return Error::success();
@@ -258,7 +298,8 @@ static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
wasm::WasmTableType TableType;
- TableType.ElemType = wasm::ValType(readVaruint32(Ctx));
+ auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
+ TableType.ElemType = ElemType;
TableType.Limits = readLimits(Ctx);
return TableType;
}
@@ -1104,26 +1145,75 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
}
Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
+ auto parseFieldDef = [&]() {
+ uint32_t TypeCode = readVaruint32((Ctx));
+ /* Discard StorageType */ parseValType(Ctx, TypeCode);
+ /* Discard Mutability */ readVaruint32(Ctx);
+ };
+
uint32_t Count = readVaruint32(Ctx);
Signatures.reserve(Count);
while (Count--) {
wasm::WasmSignature Sig;
uint8_t Form = readUint8(Ctx);
+ 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.
+ uint32_t RecSize = readVaruint32(Ctx);
+ if (RecSize == 0)
+ return make_error<GenericBinaryError>("Rec group size cannot be 0",
+ object_error::parse_failed);
+ Signatures.reserve(Signatures.size() + RecSize);
+ Count += RecSize;
+ Sig.Kind = wasm::WasmSignature::Placeholder;
+ Signatures.push_back(std::move(Sig));
+ HasUnmodeledTypes = true;
+ continue;
+ }
if (Form != wasm::WASM_TYPE_FUNC) {
- return make_error<GenericBinaryError>("invalid signature type",
- object_error::parse_failed);
+ // 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) {
+ if (Supers != 1)
+ return make_error<GenericBinaryError>(
+ "Invalid number of supertypes", object_error::parse_failed);
+ /* Discard SuperIndex */ readVaruint32(Ctx);
+ }
+ Form = readVaruint32(Ctx);
+ }
+ if (Form == wasm::WASM_TYPE_STRUCT) {
+ uint32_t FieldCount = readVaruint32(Ctx);
+ while (FieldCount--) {
+ parseFieldDef();
+ }
+ } else if (Form == wasm::WASM_TYPE_ARRAY) {
+ parseFieldDef();
+ } else {
+ return make_error<GenericBinaryError>("bad form",
+ object_error::parse_failed);
+ }
+ Sig.Kind = wasm::WasmSignature::Placeholder;
+ Signatures.push_back(std::move(Sig));
+ HasUnmodeledTypes = true;
+ continue;
}
+
uint32_t ParamCount = readVaruint32(Ctx);
Sig.Params.reserve(ParamCount);
while (ParamCount--) {
uint32_t ParamType = readUint8(Ctx);
- Sig.Params.push_back(wasm::ValType(ParamType));
+ Sig.Params.push_back(parseValType(Ctx, ParamType));
+ continue;
}
uint32_t ReturnCount = readVaruint32(Ctx);
while (ReturnCount--) {
uint32_t ReturnType = readUint8(Ctx);
- Sig.Returns.push_back(wasm::ValType(ReturnType));
+ Sig.Returns.push_back(parseValType(Ctx, ReturnType));
}
+
Signatures.push_back(std::move(Sig));
}
if (Ctx.Ptr != Ctx.End)
@@ -1164,7 +1254,8 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
NumImportedTables++;
auto ElemType = Im.Table.ElemType;
if (ElemType != wasm::ValType::FUNCREF &&
- ElemType != wasm::ValType::EXTERNREF)
+ ElemType != wasm::ValType::EXTERNREF &&
+ ElemType != wasm::ValType::OTHERREF)
return make_error<GenericBinaryError>("invalid table element type",
object_error::parse_failed);
break;
@@ -1221,7 +1312,8 @@ Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
Tables.push_back(T);
auto ElemType = Tables.back().Type.ElemType;
if (ElemType != wasm::ValType::FUNCREF &&
- ElemType != wasm::ValType::EXTERNREF) {
+ ElemType != wasm::ValType::EXTERNREF &&
+ ElemType != wasm::ValType::OTHERREF) {
return make_error<GenericBinaryError>("invalid table element type",
object_error::parse_failed);
}
@@ -1263,6 +1355,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);
}
@@ -1279,7 +1372,10 @@ 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);
if (Error Err = readInitExpr(Global.InitExpr, Ctx))
return Err;
@@ -1516,15 +1612,28 @@ 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;
+
+ if (HasTableNumber)
Segment.TableNumber = readVaruint32(Ctx);
else
Segment.TableNumber = 0;
+
if (!isValidTableNumber(Segment.TableNumber))
return make_error<GenericBinaryError>("invalid TableNumber",
object_error::parse_failed);
- if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
+ if (IsPassive || IsDeclarative) {
Segment.Offset.Extended = false;
Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
Segment.Offset.Inst.Value.Int32 = 0;
@@ -1533,33 +1642,41 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
return Err;
}
- if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
+ if (HasElemKind) {
auto ElemKind = readVaruint32(Ctx);
if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
- Segment.ElemKind = wasm::ValType(ElemKind);
+ Segment.ElemKind = parseValType(Ctx, ElemKind);
if (Segment.ElemKind != wasm::ValType::FUNCREF &&
- Segment.ElemKind != wasm::ValType::EXTERNREF) {
- return make_error<GenericBinaryError>("invalid reference type",
+ Segment.ElemKind != wasm::ValType::EXTERNREF &&
+ Segment.ElemKind != wasm::ValType::OTHERREF) {
+ return make_error<GenericBinaryError>("invalid elem type",
object_error::parse_failed);
}
} else {
if (ElemKind != 0)
- return make_error<GenericBinaryError>("invalid elemtype",
+ return make_error<GenericBinaryError>("invalid elem type",
object_error::parse_failed);
Segment.ElemKind = wasm::ValType::FUNCREF;
}
+ } else if (HasInitExprs) {
+ auto ElemType = parseValType(Ctx, readVaruint32(Ctx));
+ Segment.ElemKind = ElemType;
} else {
Segment.ElemKind = 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));
+
+ if (HasInitExprs) {
+ 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);
}