diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/wasm-binary.cpp | 68 | ||||
-rw-r--r-- | src/wasm/wasm-s-parser.cpp | 36 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 35 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 32 |
4 files changed, 169 insertions, 2 deletions
diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 90a588bb9..721884126 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1715,10 +1715,14 @@ BinaryConsts::ASTNodes WasmBinaryBuilder::readExpression(Expression*& curr) { throwError("invalid code after atomic prefix: " + std::to_string(code)); break; } - case BinaryConsts::TruncSatPrefix: { + case BinaryConsts::MiscPrefix: { auto opcode = getU32LEB(); if (maybeVisitTruncSat(curr, opcode)) break; - throwError("invalid code after nontrapping float-to-int prefix: " + std::to_string(code)); + if (maybeVisitMemoryInit(curr, opcode)) break; + if (maybeVisitDataDrop(curr, opcode)) break; + if (maybeVisitMemoryCopy(curr, opcode)) break; + if (maybeVisitMemoryFill(curr, opcode)) break; + throwError("invalid code after nontrapping float-to-int prefix: " + std::to_string(opcode)); break; } case BinaryConsts::SIMDPrefix: { @@ -2342,6 +2346,66 @@ bool WasmBinaryBuilder::maybeVisitTruncSat(Expression*& out, uint32_t code) { return true; } +bool WasmBinaryBuilder::maybeVisitMemoryInit(Expression*& out, uint32_t code) { + if (code != BinaryConsts::MemoryInit) { + return false; + } + auto* curr = allocator.alloc<MemoryInit>(); + curr->size = popNonVoidExpression(); + curr->offset = popNonVoidExpression(); + curr->dest = popNonVoidExpression(); + curr->segment = getU32LEB(); + if (getInt8() != 0) { + throwError("Unexpected nonzero memory index"); + } + curr->finalize(); + out = curr; + return true; +} + +bool WasmBinaryBuilder::maybeVisitDataDrop(Expression*& out, uint32_t code) { + if (code != BinaryConsts::DataDrop) { + return false; + } + auto* curr = allocator.alloc<DataDrop>(); + curr->segment = getU32LEB(); + curr->finalize(); + out = curr; + return true; +} + +bool WasmBinaryBuilder::maybeVisitMemoryCopy(Expression*& out, uint32_t code) { + if (code != BinaryConsts::MemoryCopy) { + return false; + } + auto* curr = allocator.alloc<MemoryCopy>(); + curr->size = popNonVoidExpression(); + curr->source = popNonVoidExpression(); + curr->dest = popNonVoidExpression(); + if (getInt8() != 0 || getInt8() != 0) { + throwError("Unexpected nonzero memory index"); + } + curr->finalize(); + out = curr; + return true; +} + +bool WasmBinaryBuilder::maybeVisitMemoryFill(Expression*& out, uint32_t code) { + if (code != BinaryConsts::MemoryFill) { + return false; + } + auto* curr = allocator.alloc<MemoryFill>(); + curr->size = popNonVoidExpression(); + curr->value = popNonVoidExpression(); + curr->dest = popNonVoidExpression(); + if (getInt8() != 0) { + throwError("Unexpected nonzero memory index"); + } + curr->finalize(); + out = curr; + return true; +} + bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) { Binary* curr; #define INT_TYPED_CODE(code) { \ diff --git a/src/wasm/wasm-s-parser.cpp b/src/wasm/wasm-s-parser.cpp index eca4c7493..d7b3824a9 100644 --- a/src/wasm/wasm-s-parser.cpp +++ b/src/wasm/wasm-s-parser.cpp @@ -786,6 +786,7 @@ Expression* SExpressionWasmBuilder::makeSetGlobal(Element& s) { Expression* SExpressionWasmBuilder::makeBlock(Element& s) { + if (!currFunction) throw ParseException("block is unallowed outside of functions"); // special-case Block, because Block nesting (in their first element) can be incredibly deep auto curr = allocator.alloc<Block>(); auto* sp = &s; @@ -1134,6 +1135,41 @@ Expression* SExpressionWasmBuilder::makeSIMDShift(Element& s, SIMDShiftOp op) { return ret; } +Expression* SExpressionWasmBuilder::makeMemoryInit(Element& s) { + auto ret = allocator.alloc<MemoryInit>(); + ret->segment = atoi(s[1]->str().c_str()); + ret->dest = parseExpression(s[2]); + ret->offset = parseExpression(s[3]); + ret->size = parseExpression(s[4]); + ret->finalize(); + return ret; +} + +Expression* SExpressionWasmBuilder::makeDataDrop(Element& s) { + auto ret = allocator.alloc<DataDrop>(); + ret->segment = atoi(s[1]->str().c_str()); + ret->finalize(); + return ret; +} + +Expression* SExpressionWasmBuilder::makeMemoryCopy(Element& s) { + auto ret = allocator.alloc<MemoryCopy>(); + ret->dest = parseExpression(s[1]); + ret->source = parseExpression(s[2]); + ret->size = parseExpression(s[3]); + ret->finalize(); + return ret; +} + +Expression* SExpressionWasmBuilder::makeMemoryFill(Element& s) { + auto ret = allocator.alloc<MemoryFill>(); + ret->dest = parseExpression(s[1]); + ret->value = parseExpression(s[2]); + ret->size = parseExpression(s[3]); + ret->finalize(); + return ret; +} + Expression* SExpressionWasmBuilder::makeIf(Element& s) { auto ret = allocator.alloc<If>(); Index i = 1; diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index f1ccb2cfa..84a0efbff 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -250,6 +250,10 @@ public: void visitSIMDShuffle(SIMDShuffle* curr); void visitSIMDBitselect(SIMDBitselect* curr); void visitSIMDShift(SIMDShift* curr); + void visitMemoryInit(MemoryInit* curr); + void visitDataDrop(DataDrop* curr); + void visitMemoryCopy(MemoryCopy* curr); + void visitMemoryFill(MemoryFill* curr); void visitBinary(Binary* curr); void visitUnary(Unary* curr); void visitSelect(Select* curr); @@ -636,6 +640,37 @@ void FunctionValidator::visitSIMDShift(SIMDShift* curr) { shouldBeEqualOrFirstIsUnreachable(curr->shift->type, i32, curr, "expected shift amount to have type i32"); } +void FunctionValidator::visitMemoryInit(MemoryInit* curr) { + shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); + shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.init must have type none"); + shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.init dest must be an i32"); + shouldBeEqualOrFirstIsUnreachable(curr->offset->type, i32, curr, "memory.init offset must be an i32"); + shouldBeEqualOrFirstIsUnreachable(curr->size->type, i32, curr, "memory.init size must be an i32"); + shouldBeTrue(curr->segment < getModule()->memory.segments.size(), curr, "memory.init segment index out of bounds"); +} + +void FunctionValidator::visitDataDrop(DataDrop* curr) { + shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); + shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "data.drop must have type none"); + shouldBeTrue(curr->segment < getModule()->memory.segments.size(), curr, "data.drop segment index out of bounds"); +} + +void FunctionValidator::visitMemoryCopy(MemoryCopy* curr) { + shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); + shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.copy must have type none"); + shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.copy dest must be an i32"); + shouldBeEqualOrFirstIsUnreachable(curr->source->type, i32, curr, "memory.copy source must be an i32"); + shouldBeEqualOrFirstIsUnreachable(curr->size->type, i32, curr, "memory.copy size must be an i32"); +} + +void FunctionValidator::visitMemoryFill(MemoryFill* curr) { + shouldBeTrue(info.features.hasBulkMemory(), curr, "Bulk memory operation (bulk memory is disabled)"); + shouldBeEqualOrFirstIsUnreachable(curr->type, none, curr, "memory.fill must have type none"); + shouldBeEqualOrFirstIsUnreachable(curr->dest->type, i32, curr, "memory.fill dest must be an i32"); + shouldBeEqualOrFirstIsUnreachable(curr->value->type, i32, curr, "memory.fill value must be an i32"); + shouldBeEqualOrFirstIsUnreachable(curr->size->type, i32, curr, "memory.fill size must be an i32"); +} + void FunctionValidator::validateMemBytes(uint8_t bytes, Type type, Expression* curr) { switch (type) { case i32: shouldBeTrue(bytes == 1 || bytes == 2 || bytes == 4, curr, "expected i32 operation to touch 1, 2, or 4 bytes"); break; diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index 0d5f3d5b5..847df5ce6 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -110,6 +110,10 @@ const char* getExpressionName(Expression* curr) { case Expression::Id::SIMDShuffleId: return "simd_shuffle"; case Expression::Id::SIMDBitselectId: return "simd_bitselect"; case Expression::Id::SIMDShiftId: return "simd_shift"; + case Expression::Id::MemoryInitId: return "memory_init"; + case Expression::Id::DataDropId: return "data_drop"; + case Expression::Id::MemoryCopyId: return "memory_copy"; + case Expression::Id::MemoryFillId: return "memory_fill"; case Expression::Id::NumExpressionIds: WASM_UNREACHABLE(); } WASM_UNREACHABLE(); @@ -464,6 +468,34 @@ void SIMDBitselect::finalize() { } } +void MemoryInit::finalize() { + assert(dest && offset && size); + type = none; + if (dest->type == unreachable || offset->type == unreachable || size->type == unreachable) { + type = unreachable; + } +} + +void DataDrop::finalize() { + type = none; +} + +void MemoryCopy::finalize() { + assert(dest && source && size); + type = none; + if (dest->type == unreachable || source->type == unreachable || size->type == unreachable) { + type = unreachable; + } +} + +void MemoryFill::finalize() { + assert(dest && value && size); + type = none; + if (dest->type == unreachable || value->type == unreachable || size->type == unreachable) { + type = unreachable; + } +} + void SIMDShift::finalize() { assert(vec && shift); type = v128; |