summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/wasm-binary.cpp68
-rw-r--r--src/wasm/wasm-s-parser.cpp36
-rw-r--r--src/wasm/wasm-validator.cpp35
-rw-r--r--src/wasm/wasm.cpp32
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;