diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 47 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 34 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 54 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 141 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 19 | ||||
-rw-r--r-- | src/wasm/wat-parser.cpp | 59 |
6 files changed, 221 insertions, 133 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 3975dd390..981932470 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -4053,10 +4053,10 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { if (maybeVisitStructSet(curr, opcode)) { break; } - if (maybeVisitArrayNew(curr, opcode)) { + if (maybeVisitArrayNewData(curr, opcode)) { break; } - if (maybeVisitArrayNewSeg(curr, opcode)) { + if (maybeVisitArrayNewElem(curr, opcode)) { break; } if (maybeVisitArrayNewFixed(curr, opcode)) { @@ -7139,7 +7139,8 @@ bool WasmBinaryBuilder::maybeVisitStructSet(Expression*& out, uint32_t code) { return true; } -bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) { +bool WasmBinaryBuilder::maybeVisitArrayNewData(Expression*& out, + uint32_t code) { if (code == BinaryConsts::ArrayNew || code == BinaryConsts::ArrayNewDefault) { auto heapType = getIndexedHeapType(); auto* size = popNonVoidExpression(); @@ -7153,22 +7154,26 @@ bool WasmBinaryBuilder::maybeVisitArrayNew(Expression*& out, uint32_t code) { return false; } -bool WasmBinaryBuilder::maybeVisitArrayNewSeg(Expression*& out, uint32_t code) { +bool WasmBinaryBuilder::maybeVisitArrayNewElem(Expression*& out, + uint32_t code) { if (code == BinaryConsts::ArrayNewData || code == BinaryConsts::ArrayNewElem) { - auto op = code == BinaryConsts::ArrayNewData ? NewData : NewElem; + auto isData = code == BinaryConsts::ArrayNewData; auto heapType = getIndexedHeapType(); auto segIdx = getU32LEB(); auto* size = popNonVoidExpression(); auto* offset = popNonVoidExpression(); - auto* built = - Builder(wasm).makeArrayNewSeg(op, heapType, Name(), offset, size); - if (op == NewData) { - dataRefs[segIdx].push_back(&built->segment); + if (isData) { + auto* curr = + Builder(wasm).makeArrayNewData(heapType, Name(), offset, size); + dataRefs[segIdx].push_back(&curr->segment); + out = curr; } else { - elemRefs[segIdx].push_back(&built->segment); + auto* curr = + Builder(wasm).makeArrayNewElem(heapType, Name(), offset, size); + elemRefs[segIdx].push_back(&curr->segment); + out = curr; } - out = built; return true; } return false; @@ -7271,13 +7276,12 @@ bool WasmBinaryBuilder::maybeVisitArrayFill(Expression*& out, uint32_t code) { } bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) { - ArrayInitOp op; + bool isData = true; switch (code) { case BinaryConsts::ArrayInitData: - op = InitData; break; case BinaryConsts::ArrayInitElem: - op = InitElem; + isData = false; break; default: return false; @@ -7289,14 +7293,17 @@ bool WasmBinaryBuilder::maybeVisitArrayInit(Expression*& out, uint32_t code) { auto* index = popNonVoidExpression(); auto* ref = popNonVoidExpression(); validateHeapTypeUsingChild(ref, heapType); - auto* built = - Builder(wasm).makeArrayInit(op, Name(), ref, index, offset, size); - if (op == InitData) { - dataRefs[segIdx].push_back(&built->segment); + if (isData) { + auto* curr = + Builder(wasm).makeArrayInitData(Name(), ref, index, offset, size); + dataRefs[segIdx].push_back(&curr->segment); + out = curr; } else { - elemRefs[segIdx].push_back(&built->segment); + auto* curr = + Builder(wasm).makeArrayInitElem(Name(), ref, index, offset, size); + elemRefs[segIdx].push_back(&curr->segment); + out = curr; } - out = built; return true; } diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index 968c8bd45..44008bb75 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -2974,14 +2974,20 @@ Expression* SExpressionWasmBuilder::makeArrayNew(Element& s, bool default_) { return Builder(wasm).makeArrayNew(heapType, size, init); } -Expression* SExpressionWasmBuilder::makeArrayNewSeg(Element& s, - ArrayNewSegOp op) { +Expression* SExpressionWasmBuilder::makeArrayNewData(Element& s) { auto heapType = parseHeapType(*s[1]); - Name seg = - op == NewData ? getDataSegmentName(*s[2]) : getElemSegmentName(*s[2]); + Name seg = getDataSegmentName(*s[2]); Expression* offset = parseExpression(*s[3]); Expression* size = parseExpression(*s[4]); - return Builder(wasm).makeArrayNewSeg(op, heapType, seg, offset, size); + return Builder(wasm).makeArrayNewData(heapType, seg, offset, size); +} + +Expression* SExpressionWasmBuilder::makeArrayNewElem(Element& s) { + auto heapType = parseHeapType(*s[1]); + Name seg = getElemSegmentName(*s[2]); + Expression* offset = parseExpression(*s[3]); + Expression* size = parseExpression(*s[4]); + return Builder(wasm).makeArrayNewElem(heapType, seg, offset, size); } Expression* SExpressionWasmBuilder::makeArrayNewFixed(Element& s) { @@ -3051,16 +3057,26 @@ Expression* SExpressionWasmBuilder::makeArrayFill(Element& s) { return Builder(wasm).makeArrayFill(ref, index, value, size); } -Expression* SExpressionWasmBuilder::makeArrayInit(Element& s, ArrayInitOp op) { +Expression* SExpressionWasmBuilder::makeArrayInitData(Element& s) { + auto heapType = parseHeapType(*s[1]); + auto seg = getDataSegmentName(*s[2]); + auto ref = parseExpression(*s[3]); + validateHeapTypeUsingChild(ref, heapType, s); + auto index = parseExpression(*s[4]); + auto offset = parseExpression(*s[5]); + auto size = parseExpression(*s[6]); + return Builder(wasm).makeArrayInitData(seg, ref, index, offset, size); +} + +Expression* SExpressionWasmBuilder::makeArrayInitElem(Element& s) { auto heapType = parseHeapType(*s[1]); - auto seg = - op == InitData ? getDataSegmentName(*s[2]) : getElemSegmentName(*s[2]); + auto seg = getElemSegmentName(*s[2]); auto ref = parseExpression(*s[3]); validateHeapTypeUsingChild(ref, heapType, s); auto index = parseExpression(*s[4]); auto offset = parseExpression(*s[5]); auto size = parseExpression(*s[6]); - return Builder(wasm).makeArrayInit(op, seg, ref, index, offset, size); + return Builder(wasm).makeArrayInitElem(seg, ref, index, offset, size); } Expression* SExpressionWasmBuilder::makeRefAs(Element& s, RefAsOp op) { diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 286b049aa..14c24d807 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -2118,22 +2118,18 @@ void BinaryInstWriter::visitArrayNew(ArrayNew* curr) { parent.writeIndexedHeapType(curr->type.getHeapType()); } -void BinaryInstWriter::visitArrayNewSeg(ArrayNewSeg* curr) { +void BinaryInstWriter::visitArrayNewData(ArrayNewData* curr) { o << int8_t(BinaryConsts::GCPrefix); - switch (curr->op) { - case NewData: - o << U32LEB(BinaryConsts::ArrayNewData); - parent.writeIndexedHeapType(curr->type.getHeapType()); - o << U32LEB(parent.getDataSegmentIndex(curr->segment)); - break; - case NewElem: - o << U32LEB(BinaryConsts::ArrayNewElem); - parent.writeIndexedHeapType(curr->type.getHeapType()); - o << U32LEB(parent.getElementSegmentIndex(curr->segment)); - break; - default: - WASM_UNREACHABLE("unexpected op"); - } + o << U32LEB(BinaryConsts::ArrayNewData); + parent.writeIndexedHeapType(curr->type.getHeapType()); + o << U32LEB(parent.getDataSegmentIndex(curr->segment)); +} + +void BinaryInstWriter::visitArrayNewElem(ArrayNewElem* curr) { + o << int8_t(BinaryConsts::GCPrefix); + o << U32LEB(BinaryConsts::ArrayNewElem); + parent.writeIndexedHeapType(curr->type.getHeapType()); + o << U32LEB(parent.getElementSegmentIndex(curr->segment)); } void BinaryInstWriter::visitArrayNewFixed(ArrayNewFixed* curr) { @@ -2194,26 +2190,26 @@ void BinaryInstWriter::visitArrayFill(ArrayFill* curr) { parent.writeIndexedHeapType(curr->ref->type.getHeapType()); } -void BinaryInstWriter::visitArrayInit(ArrayInit* curr) { +void BinaryInstWriter::visitArrayInitData(ArrayInitData* curr) { if (curr->ref->type.isNull()) { emitUnreachable(); return; } o << int8_t(BinaryConsts::GCPrefix); - switch (curr->op) { - case InitData: - o << U32LEB(BinaryConsts::ArrayInitData); - parent.writeIndexedHeapType(curr->ref->type.getHeapType()); - o << U32LEB(parent.getDataSegmentIndex(curr->segment)); - break; - case InitElem: - o << U32LEB(BinaryConsts::ArrayInitElem); - parent.writeIndexedHeapType(curr->ref->type.getHeapType()); - o << U32LEB(parent.getElementSegmentIndex(curr->segment)); - break; - default: - WASM_UNREACHABLE("unexpected op"); + o << U32LEB(BinaryConsts::ArrayInitData); + parent.writeIndexedHeapType(curr->ref->type.getHeapType()); + o << U32LEB(parent.getDataSegmentIndex(curr->segment)); +} + +void BinaryInstWriter::visitArrayInitElem(ArrayInitElem* curr) { + if (curr->ref->type.isNull()) { + emitUnreachable(); + return; } + o << int8_t(BinaryConsts::GCPrefix); + o << U32LEB(BinaryConsts::ArrayInitElem); + parent.writeIndexedHeapType(curr->ref->type.getHeapType()); + o << U32LEB(parent.getElementSegmentIndex(curr->segment)); } void BinaryInstWriter::visitRefAs(RefAs* curr) { diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index 845f0f6b6..318657034 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -22,6 +22,7 @@ #include "ir/eh-utils.h" #include "ir/features.h" #include "ir/find_all.h" +#include "ir/gc-type-utils.h" #include "ir/global-utils.h" #include "ir/intrinsics.h" #include "ir/local-graph.h" @@ -456,14 +457,18 @@ public: void visitStructGet(StructGet* curr); void visitStructSet(StructSet* curr); void visitArrayNew(ArrayNew* curr); - void visitArrayNewSeg(ArrayNewSeg* curr); + template<typename ArrayNew> void visitArrayNew(ArrayNew* curr); + void visitArrayNewData(ArrayNewData* curr); + void visitArrayNewElem(ArrayNewElem* curr); void visitArrayNewFixed(ArrayNewFixed* curr); void visitArrayGet(ArrayGet* curr); void visitArraySet(ArraySet* curr); void visitArrayLen(ArrayLen* curr); void visitArrayCopy(ArrayCopy* curr); void visitArrayFill(ArrayFill* curr); - void visitArrayInit(ArrayInit* curr); + template<typename ArrayInit> void visitArrayInit(ArrayInit* curr); + void visitArrayInitData(ArrayInitData* curr); + void visitArrayInitElem(ArrayInitElem* curr); void visitFunction(Function* curr); // helpers @@ -2703,7 +2708,8 @@ void FunctionValidator::visitArrayNew(ArrayNew* curr) { } } -void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { +template<typename ArrayNew> +void FunctionValidator::visitArrayNew(ArrayNew* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, "array.new_{data, elem} requires gc [--enable-gc]"); @@ -2717,24 +2723,6 @@ void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { Type(Type::i32), curr, "array.new_{data, elem} size must be an i32"); - switch (curr->op) { - case NewData: - if (!shouldBeTrue(getModule()->getDataSegment(curr->segment), - curr, - "array.new_data segment should exist")) { - return; - } - break; - case NewElem: - if (!shouldBeTrue(getModule()->getElementSegment(curr->segment), - curr, - "array.new_elem segment should exist")) { - return; - } - break; - default: - WASM_UNREACHABLE("unexpected op"); - } if (curr->type == Type::unreachable) { return; } @@ -2748,26 +2736,49 @@ void FunctionValidator::visitArrayNewSeg(ArrayNewSeg* curr) { if (!shouldBeTrue( heapType.isArray(), curr, - "array.new_{data, elem} type shoudl be an array reference")) { + "array.new_{data, elem} type should be an array reference")) { return; } - auto elemType = heapType.getArray().element.type; - switch (curr->op) { - case NewData: - shouldBeTrue(elemType.isNumber(), - curr, - "array.new_data result element type should be numeric"); - break; - case NewElem: - shouldBeSubType(getModule()->getElementSegment(curr->segment)->type, - elemType, - curr, - "array.new_elem segment type should be a subtype of the " - "result element type"); - break; - default: - WASM_UNREACHABLE("unexpected op"); +} + +void FunctionValidator::visitArrayNewData(ArrayNewData* curr) { + visitArrayNew(curr); + + if (!shouldBeTrue(getModule()->getDataSegment(curr->segment), + curr, + "array.new_data segment should exist")) { + return; } + + auto field = GCTypeUtils::getField(curr->type); + if (!field) { + // A bottom type, or unreachable. + return; + } + shouldBeTrue(field->type.isNumber(), + curr, + "array.new_data result element type should be numeric"); +} + +void FunctionValidator::visitArrayNewElem(ArrayNewElem* curr) { + visitArrayNew(curr); + + if (!shouldBeTrue(getModule()->getElementSegment(curr->segment), + curr, + "array.new_elem segment should exist")) { + return; + } + + auto field = GCTypeUtils::getField(curr->type); + if (!field) { + // A bottom type, or unreachable. + return; + } + shouldBeSubType(getModule()->getElementSegment(curr->segment)->type, + field->type, + curr, + "array.new_elem segment type should be a subtype of the " + "result element type"); } void FunctionValidator::visitArrayNewFixed(ArrayNewFixed* curr) { @@ -2956,6 +2967,7 @@ void FunctionValidator::visitArrayFill(ArrayFill* curr) { element.mutable_, curr, "array.fill destination must be mutable"); } +template<typename ArrayInit> void FunctionValidator::visitArrayInit(ArrayInit* curr) { shouldBeTrue(getModule()->features.hasGC(), curr, @@ -2991,24 +3003,43 @@ void FunctionValidator::visitArrayInit(ArrayInit* curr) { auto element = heapType.getArray().element; shouldBeTrue( element.mutable_, curr, "array.init_* destination must be mutable"); - if (curr->op == InitData) { - shouldBeTrue(getModule()->getDataSegmentOrNull(curr->segment), - curr, - "array.init_data segment must exist"); - shouldBeTrue(element.type.isNumber(), - curr, - "array.init_data destination must be numeric"); - } else { - assert(curr->op == InitElem); - auto* seg = getModule()->getElementSegmentOrNull(curr->segment); - if (!shouldBeTrue(seg, curr, "array.init_elem segment must exist")) { - return; - } - shouldBeSubType(seg->type, - element.type, - curr, - "array.init_elem segment type must match destination type"); +} + +void FunctionValidator::visitArrayInitData(ArrayInitData* curr) { + visitArrayInit(curr); + + shouldBeTrue(getModule()->getDataSegmentOrNull(curr->segment), + curr, + "array.init_data segment must exist"); + + auto field = GCTypeUtils::getField(curr->ref->type); + if (!field) { + // A bottom type, or unreachable. + return; } + shouldBeTrue(field->type.isNumber(), + curr, + "array.init_data destination must be numeric"); +} + +void FunctionValidator::visitArrayInitElem(ArrayInitElem* curr) { + visitArrayInit(curr); + + auto* seg = getModule()->getElementSegmentOrNull(curr->segment); + if (!shouldBeTrue(seg, curr, "array.init_elem segment must exist")) { + return; + } + + auto field = GCTypeUtils::getField(curr->ref->type); + if (!field) { + // A bottom type, or unreachable. + return; + } + + shouldBeSubType(seg->type, + field->type, + curr, + "array.init_elem segment type must match destination type"); } void FunctionValidator::visitFunction(Function* curr) { diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index f3e345895..c3f262998 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -1057,7 +1057,13 @@ void ArrayNew::finalize() { } } -void ArrayNewSeg::finalize() { +void ArrayNewData::finalize() { + if (offset->type == Type::unreachable || size->type == Type::unreachable) { + type = Type::unreachable; + } +} + +void ArrayNewElem::finalize() { if (offset->type == Type::unreachable || size->type == Type::unreachable) { type = Type::unreachable; } @@ -1118,7 +1124,16 @@ void ArrayFill::finalize() { } } -void ArrayInit::finalize() { +void ArrayInitData::finalize() { + if (ref->type == Type::unreachable || index->type == Type::unreachable || + offset->type == Type::unreachable || size->type == Type::unreachable) { + type = Type::unreachable; + } else { + type = Type::none; + } +} + +void ArrayInitElem::finalize() { if (ref->type == Type::unreachable || index->type == Type::unreachable || offset->type == Type::unreachable || size->type == Type::unreachable) { type = Type::unreachable; diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index 51527b5e3..528d0d1af 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -789,6 +789,10 @@ struct NullInstrParserCtx { InstrT makeArrayNewData(Index, HeapTypeT, DataIdxT) { return Ok{}; } + template<typename HeapTypeT> + InstrT makeArrayNewElem(Index, HeapTypeT, DataIdxT) { + return Ok{}; + } template<typename HeapTypeT> InstrT makeArrayGet(Index, HeapTypeT, bool) { return Ok{}; } @@ -2156,8 +2160,18 @@ struct ParseDefsCtx : TypeParserCtx<ParseDefsCtx> { CHECK_ERR(size); auto offset = pop(pos); CHECK_ERR(offset); - return push(pos, - builder.makeArrayNewSeg(NewData, type, data, *offset, *size)); + return push(pos, builder.makeArrayNewData(type, data, *offset, *size)); + } + + Result<> makeArrayNewElem(Index pos, HeapType type, Name data) { + if (!type.isArray()) { + return in.err(pos, "expected array type annotation"); + } + auto size = pop(pos); + CHECK_ERR(size); + auto offset = pop(pos); + CHECK_ERR(offset); + return push(pos, builder.makeArrayNewElem(type, data, *offset, *size)); } Result<> makeArrayGet(Index pos, HeapType type, bool signed_) { @@ -2380,7 +2394,9 @@ template<typename Ctx> Result<typename Ctx::InstrT> makeStructSet(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayNew(Ctx&, Index, bool default_); template<typename Ctx> -Result<typename Ctx::InstrT> makeArrayNewSeg(Ctx&, Index, ArrayNewSegOp op); +Result<typename Ctx::InstrT> makeArrayNewData(Ctx&, Index); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayNewElem(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayNewFixed(Ctx&, Index); template<typename Ctx> @@ -2390,7 +2406,9 @@ template<typename Ctx> Result<typename Ctx::InstrT> makeArrayLen(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayCopy(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeArrayFill(Ctx&, Index); template<typename Ctx> -Result<typename Ctx::InstrT> makeArrayInit(Ctx&, Index, ArrayInitOp); +Result<typename Ctx::InstrT> makeArrayInitData(Ctx&, Index); +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInitElem(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeRefAs(Ctx&, Index, RefAsOp op); template<typename Ctx> @@ -3528,20 +3546,21 @@ Result<typename Ctx::InstrT> makeArrayNew(Ctx& ctx, Index pos, bool default_) { } template<typename Ctx> -Result<typename Ctx::InstrT> -makeArrayNewSeg(Ctx& ctx, Index pos, ArrayNewSegOp op) { +Result<typename Ctx::InstrT> makeArrayNewData(Ctx& ctx, Index pos) { auto type = typeidx(ctx); CHECK_ERR(type); - switch (op) { - case NewData: { - auto data = dataidx(ctx); - CHECK_ERR(data); - return ctx.makeArrayNewData(pos, *type, *data); - } - case NewElem: - return ctx.in.err("unimplemented instruction"); - } - WASM_UNREACHABLE("unexpected op"); + auto data = dataidx(ctx); + CHECK_ERR(data); + return ctx.makeArrayNewData(pos, *type, *data); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayNewElem(Ctx& ctx, Index pos) { + auto type = typeidx(ctx); + CHECK_ERR(type); + auto data = dataidx(ctx); + CHECK_ERR(data); + return ctx.makeArrayNewElem(pos, *type, *data); } template<typename Ctx> @@ -3585,8 +3604,12 @@ Result<typename Ctx::InstrT> makeArrayFill(Ctx& ctx, Index pos) { } template<typename Ctx> -Result<typename Ctx::InstrT> -makeArrayInit(Ctx& ctx, Index pos, ArrayInitOp op) { +Result<typename Ctx::InstrT> makeArrayInitData(Ctx& ctx, Index pos) { + return ctx.in.err("unimplemented instruction"); +} + +template<typename Ctx> +Result<typename Ctx::InstrT> makeArrayInitElem(Ctx& ctx, Index pos) { return ctx.in.err("unimplemented instruction"); } |