diff options
author | Yuhan Deng <31569419+yhdengh@users.noreply.github.com> | 2021-11-30 14:04:40 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-11-30 22:04:40 +0000 |
commit | cf1e138ba9cde79d51f56d873e10b7ac9e4481b1 (patch) | |
tree | 22451a2d589797e4fd3c653e90ab7859234b38d0 /src | |
parent | f65fadeedff3458e1dd9c157553cd0ed891683dd (diff) | |
download | wabt-cf1e138ba9cde79d51f56d873e10b7ac9e4481b1.tar.gz wabt-cf1e138ba9cde79d51f56d873e10b7ac9e4481b1.tar.bz2 wabt-cf1e138ba9cde79d51f56d873e10b7ac9e4481b1.zip |
Add multi-memory feature support (#1751)
Diffstat (limited to 'src')
-rw-r--r-- | src/binary-reader-ir.cc | 41 | ||||
-rw-r--r-- | src/binary-reader-logging.cc | 23 | ||||
-rw-r--r-- | src/binary-reader-logging.h | 12 | ||||
-rw-r--r-- | src/binary-reader-nop.h | 16 | ||||
-rw-r--r-- | src/binary-reader.cc | 124 | ||||
-rw-r--r-- | src/binary-reader.h | 12 | ||||
-rw-r--r-- | src/binary-writer.cc | 74 | ||||
-rw-r--r-- | src/c-writer.cc | 29 | ||||
-rw-r--r-- | src/feature.def | 1 | ||||
-rw-r--r-- | src/interp/binary-reader-interp.cc | 56 | ||||
-rw-r--r-- | src/ir.h | 68 | ||||
-rw-r--r-- | src/resolve-names.cc | 38 | ||||
-rw-r--r-- | src/shared-validator.cc | 31 | ||||
-rw-r--r-- | src/shared-validator.h | 14 | ||||
-rw-r--r-- | src/validator.cc | 15 | ||||
-rw-r--r-- | src/wast-parser.cc | 98 | ||||
-rw-r--r-- | src/wast-parser.h | 9 | ||||
-rw-r--r-- | src/wat-writer.cc | 67 |
18 files changed, 557 insertions, 171 deletions
diff --git a/src/binary-reader-ir.cc b/src/binary-reader-ir.cc index f454174b..27e97c85 100644 --- a/src/binary-reader-ir.cc +++ b/src/binary-reader-ir.cc @@ -165,18 +165,19 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnI64ConstExpr(uint64_t value) override; Result OnIfExpr(Type sig_type) override; Result OnLoadExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override; Result OnLocalGetExpr(Index local_index) override; Result OnLocalSetExpr(Index local_index) override; Result OnLocalTeeExpr(Index local_index) override; Result OnLoopExpr(Type sig_type) override; - Result OnMemoryCopyExpr() override; + Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override; Result OnDataDropExpr(Index segment_index) override; - Result OnMemoryFillExpr() override; - Result OnMemoryGrowExpr() override; - Result OnMemoryInitExpr(Index segment_index) override; - Result OnMemorySizeExpr() override; + Result OnMemoryFillExpr(Index memidx) override; + Result OnMemoryGrowExpr(Index memidx) override; + Result OnMemoryInitExpr(Index segment_index, Index memidx) override; + Result OnMemorySizeExpr(Index memidx) override; Result OnTableCopyExpr(Index dst_index, Index src_index) override; Result OnElemDropExpr(Index segment_index) override; Result OnTableInitExpr(Index segment_index, Index table_index) override; @@ -193,6 +194,7 @@ class BinaryReaderIR : public BinaryReaderNop { Result OnReturnExpr() override; Result OnSelectExpr(Index result_count, Type* result_types) override; Result OnStoreExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override; Result OnThrowExpr(Index tag_index) override; @@ -873,9 +875,11 @@ Result BinaryReaderIR::OnIfExpr(Type sig_type) { } Result BinaryReaderIR::OnLoadExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) { - return AppendExpr(MakeUnique<LoadExpr>(opcode, 1 << alignment_log2, offset)); + return AppendExpr( + MakeUnique<LoadExpr>(opcode, Var(memidx), 1 << alignment_log2, offset)); } Result BinaryReaderIR::OnLoopExpr(Type sig_type) { @@ -887,28 +891,29 @@ Result BinaryReaderIR::OnLoopExpr(Type sig_type) { return Result::Ok; } -Result BinaryReaderIR::OnMemoryCopyExpr() { - return AppendExpr(MakeUnique<MemoryCopyExpr>()); +Result BinaryReaderIR::OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) { + return AppendExpr( + MakeUnique<MemoryCopyExpr>(Var(srcmemidx), Var(destmemidx))); } Result BinaryReaderIR::OnDataDropExpr(Index segment) { return AppendExpr(MakeUnique<DataDropExpr>(Var(segment))); } -Result BinaryReaderIR::OnMemoryFillExpr() { - return AppendExpr(MakeUnique<MemoryFillExpr>()); +Result BinaryReaderIR::OnMemoryFillExpr(Index memidx) { + return AppendExpr(MakeUnique<MemoryFillExpr>(Var(memidx))); } -Result BinaryReaderIR::OnMemoryGrowExpr() { - return AppendExpr(MakeUnique<MemoryGrowExpr>()); +Result BinaryReaderIR::OnMemoryGrowExpr(Index memidx) { + return AppendExpr(MakeUnique<MemoryGrowExpr>(Var(memidx))); } -Result BinaryReaderIR::OnMemoryInitExpr(Index segment) { - return AppendExpr(MakeUnique<MemoryInitExpr>(Var(segment))); +Result BinaryReaderIR::OnMemoryInitExpr(Index segment, Index memidx) { + return AppendExpr(MakeUnique<MemoryInitExpr>(Var(segment), Var(memidx))); } -Result BinaryReaderIR::OnMemorySizeExpr() { - return AppendExpr(MakeUnique<MemorySizeExpr>()); +Result BinaryReaderIR::OnMemorySizeExpr(Index memidx) { + return AppendExpr(MakeUnique<MemorySizeExpr>(Var(memidx))); } Result BinaryReaderIR::OnTableCopyExpr(Index dst_index, Index src_index) { @@ -983,9 +988,11 @@ Result BinaryReaderIR::OnLocalSetExpr(Index local_index) { } Result BinaryReaderIR::OnStoreExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) { - return AppendExpr(MakeUnique<StoreExpr>(opcode, 1 << alignment_log2, offset)); + return AppendExpr( + MakeUnique<StoreExpr>(opcode, Var(memidx), 1 << alignment_log2, offset)); } Result BinaryReaderIR::OnThrowExpr(Index tag_index) { diff --git a/src/binary-reader-logging.cc b/src/binary-reader-logging.cc index 9fa906ba..6e0779a5 100644 --- a/src/binary-reader-logging.cc +++ b/src/binary-reader-logging.cc @@ -748,6 +748,15 @@ Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) { return reader_->name(opcode, alignment_log2, offset); \ } +#define DEFINE_MEMORY_LOAD_STORE_OPCODE(name) \ + Result BinaryReaderLogging::name(Opcode opcode, Index memidx, \ + Address alignment_log2, Address offset) { \ + LOGF(#name "(opcode: \"%s\" (%u), memidx: %" PRIindex \ + ", align log2: %" PRIaddress ", offset: %" PRIaddress ")\n", \ + opcode.GetName(), opcode.GetCode(), memidx, alignment_log2, offset); \ + return reader_->name(opcode, memidx, alignment_log2, offset); \ + } + #define DEFINE_SIMD_LOAD_STORE_LANE_OPCODE(name) \ Result BinaryReaderLogging::name(Opcode opcode, Address alignment_log2, \ Address offset, uint64_t value) { \ @@ -828,16 +837,16 @@ DEFINE0(OnElseExpr) DEFINE0(OnEndExpr) DEFINE_INDEX_DESC(OnGlobalGetExpr, "index") DEFINE_INDEX_DESC(OnGlobalSetExpr, "index") -DEFINE_LOAD_STORE_OPCODE(OnLoadExpr); +DEFINE_MEMORY_LOAD_STORE_OPCODE(OnLoadExpr); DEFINE_INDEX_DESC(OnLocalGetExpr, "index") DEFINE_INDEX_DESC(OnLocalSetExpr, "index") DEFINE_INDEX_DESC(OnLocalTeeExpr, "index") -DEFINE0(OnMemoryCopyExpr) +DEFINE_INDEX_INDEX(OnMemoryCopyExpr, "src_memory_index", "dest_memory_index") DEFINE_INDEX(OnDataDropExpr) -DEFINE0(OnMemoryFillExpr) -DEFINE0(OnMemoryGrowExpr) -DEFINE_INDEX(OnMemoryInitExpr) -DEFINE0(OnMemorySizeExpr) +DEFINE_INDEX(OnMemoryFillExpr) +DEFINE_INDEX(OnMemoryGrowExpr) +DEFINE_INDEX_INDEX(OnMemoryInitExpr, "segment_index", "memory_index") +DEFINE_INDEX(OnMemorySizeExpr) DEFINE_INDEX_INDEX(OnTableCopyExpr, "dst_index", "src_index") DEFINE_INDEX(OnElemDropExpr) DEFINE_INDEX_INDEX(OnTableInitExpr, "segment_index", "table_index") @@ -857,7 +866,7 @@ DEFINE_INDEX_INDEX(OnReturnCallIndirectExpr, "sig_index", "table_index") DEFINE0(OnReturnExpr) DEFINE_LOAD_STORE_OPCODE(OnLoadSplatExpr); DEFINE_LOAD_STORE_OPCODE(OnLoadZeroExpr); -DEFINE_LOAD_STORE_OPCODE(OnStoreExpr); +DEFINE_MEMORY_LOAD_STORE_OPCODE(OnStoreExpr); DEFINE_INDEX_DESC(OnThrowExpr, "tag_index") DEFINE0(OnUnreachableExpr) DEFINE_OPCODE(OnUnaryExpr) diff --git a/src/binary-reader-logging.h b/src/binary-reader-logging.h index 41ecf07d..d1531b35 100644 --- a/src/binary-reader-logging.h +++ b/src/binary-reader-logging.h @@ -185,18 +185,19 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnI64ConstExpr(uint64_t value) override; Result OnIfExpr(Type sig_type) override; Result OnLoadExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override; Result OnLocalGetExpr(Index local_index) override; Result OnLocalSetExpr(Index local_index) override; Result OnLocalTeeExpr(Index local_index) override; Result OnLoopExpr(Type sig_type) override; - Result OnMemoryCopyExpr() override; + Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override; Result OnDataDropExpr(Index segment_index) override; - Result OnMemoryFillExpr() override; - Result OnMemoryGrowExpr() override; - Result OnMemoryInitExpr(Index segment_index) override; - Result OnMemorySizeExpr() override; + Result OnMemoryFillExpr(Index memidx) override; + Result OnMemoryGrowExpr(Index memidx) override; + Result OnMemoryInitExpr(Index segment_index, Index memidx) override; + Result OnMemorySizeExpr(Index memidx) override; Result OnTableCopyExpr(Index dst_index, Index src_index) override; Result OnElemDropExpr(Index segment_index) override; Result OnTableInitExpr(Index segment_index, Index table_index) override; @@ -215,6 +216,7 @@ class BinaryReaderLogging : public BinaryReaderDelegate { Result OnReturnExpr() override; Result OnSelectExpr(Index result_count, Type* result_types) override; Result OnStoreExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override; Result OnThrowExpr(Index tag_index) override; diff --git a/src/binary-reader-nop.h b/src/binary-reader-nop.h index 167ea8c7..256ac920 100644 --- a/src/binary-reader-nop.h +++ b/src/binary-reader-nop.h @@ -256,6 +256,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnI64ConstExpr(uint64_t value) override { return Result::Ok; } Result OnIfExpr(Type sig_type) override { return Result::Ok; } Result OnLoadExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override { return Result::Ok; @@ -264,12 +265,16 @@ class BinaryReaderNop : public BinaryReaderDelegate { Result OnLocalSetExpr(Index local_index) override { return Result::Ok; } Result OnLocalTeeExpr(Index local_index) override { return Result::Ok; } Result OnLoopExpr(Type sig_type) override { return Result::Ok; } - Result OnMemoryCopyExpr() override { return Result::Ok; } + Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override { + return Result::Ok; + } Result OnDataDropExpr(Index segment_index) override { return Result::Ok; } - Result OnMemoryFillExpr() override { return Result::Ok; } - Result OnMemoryGrowExpr() override { return Result::Ok; } - Result OnMemoryInitExpr(Index segment_index) override { return Result::Ok; } - Result OnMemorySizeExpr() override { return Result::Ok; } + Result OnMemoryFillExpr(Index memidx) override { return Result::Ok; } + Result OnMemoryGrowExpr(Index memidx) override { return Result::Ok; } + Result OnMemoryInitExpr(Index segment_index, Index memidx) override { + return Result::Ok; + } + Result OnMemorySizeExpr(Index memidx) override { return Result::Ok; } Result OnTableCopyExpr(Index dst_index, Index src_index) override { return Result::Ok; } @@ -294,6 +299,7 @@ class BinaryReaderNop : public BinaryReaderDelegate { return Result::Ok; } Result OnStoreExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override { return Result::Ok; diff --git a/src/binary-reader.cc b/src/binary-reader.cc index 9c6aeffb..c146c7ec 100644 --- a/src/binary-reader.cc +++ b/src/binary-reader.cc @@ -110,6 +110,7 @@ class BinaryReader { Result ReadIndex(Index* index, const char* desc) WABT_WARN_UNUSED; Result ReadOffset(Offset* offset, const char* desc) WABT_WARN_UNUSED; Result ReadAlignment(Address* align_log2, const char* desc) WABT_WARN_UNUSED; + Result ReadMemidx(Index* memidx, const char* desc) WABT_WARN_UNUSED; Result ReadCount(Index* index, const char* desc) WABT_WARN_UNUSED; Result ReadField(TypeMut* out_value) WABT_WARN_UNUSED; @@ -398,7 +399,8 @@ Result BinaryReader::ReadOffset(Offset* offset, const char* desc) { Result BinaryReader::ReadAlignment(Address* alignment_log2, const char* desc) { uint32_t value; CHECK_RESULT(ReadU32Leb128(&value, desc)); - if (value >= 32) { + if (value >= 128 || + (value >= 32 && !options_.features.multi_memory_enabled())) { PrintError("invalid %s: %u", desc, value); return Result::Error; } @@ -406,6 +408,13 @@ Result BinaryReader::ReadAlignment(Address* alignment_log2, const char* desc) { return Result::Ok; } +Result BinaryReader::ReadMemidx(Index* memidx, const char* desc) { + CHECK_RESULT(ReadIndex(memidx, desc)); + ERROR_UNLESS(*memidx < memories.size(), "memory index %u out of range", + *memidx); + return Result::Ok; +} + Result BinaryReader::ReadCount(Index* count, const char* desc) { CHECK_RESULT(ReadIndex(count, desc)); @@ -953,8 +962,20 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment")); Address offset; CHECK_RESULT(ReadAddress(&offset, 0, "load offset")); - CALLBACK(OnLoadExpr, opcode, alignment_log2, offset); - CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + Index memidx = 0; + if (alignment_log2 >> 6) { + ERROR_IF(!options_.features.multi_memory_enabled(), + "multi_memory not allowed"); + CHECK_RESULT(ReadMemidx(&memidx, "store memidx")); + alignment_log2 = alignment_log2 & ((1 << 6) - 1); + } + + CALLBACK(OnLoadExpr, opcode, memidx, alignment_log2, offset); + if (memidx) { + CALLBACK(OnOpcodeUint32Uint32Uint32, alignment_log2, offset, memidx); + } else { + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + } break; } @@ -972,27 +993,48 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { CHECK_RESULT(ReadAlignment(&alignment_log2, "store alignment")); Address offset; CHECK_RESULT(ReadAddress(&offset, 0, "store offset")); + Index memidx = 0; + if (alignment_log2 >> 6) { + ERROR_IF(!options_.features.multi_memory_enabled(), + "multi_memory not allowed"); + CHECK_RESULT(ReadMemidx(&memidx, "store memidx")); + alignment_log2 = alignment_log2 & ((1 << 6) - 1); + } - CALLBACK(OnStoreExpr, opcode, alignment_log2, offset); - CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + CALLBACK(OnStoreExpr, opcode, memidx, alignment_log2, offset); + if (memidx) { + CALLBACK(OnOpcodeUint32Uint32Uint32, alignment_log2, offset, memidx); + } else { + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + } break; } case Opcode::MemorySize: { - uint8_t reserved; - CHECK_RESULT(ReadU8(&reserved, "memory.size reserved")); - ERROR_UNLESS(reserved == 0, "memory.size reserved value must be 0"); - CALLBACK0(OnMemorySizeExpr); - CALLBACK(OnOpcodeUint32, reserved); + Index memidx = 0; + if (!options_.features.multi_memory_enabled()) { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "memory.size reserved")); + ERROR_UNLESS(reserved == 0, "memory.size reserved value must be 0"); + } else { + CHECK_RESULT(ReadMemidx(&memidx, "memory.size memidx")); + } + CALLBACK(OnMemorySizeExpr, memidx); + CALLBACK(OnOpcodeUint32, memidx); break; } case Opcode::MemoryGrow: { - uint8_t reserved; - CHECK_RESULT(ReadU8(&reserved, "memory.grow reserved")); - ERROR_UNLESS(reserved == 0, "memory.grow reserved value must be 0"); - CALLBACK0(OnMemoryGrowExpr); - CALLBACK(OnOpcodeUint32, reserved); + Index memidx = 0; + if (!options_.features.multi_memory_enabled()) { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "memory.grow reserved")); + ERROR_UNLESS(reserved == 0, "memory.grow reserved value must be 0"); + } else { + CHECK_RESULT(ReadMemidx(&memidx, "memory.grow memidx")); + } + CALLBACK(OnMemoryGrowExpr, memidx); + CALLBACK(OnOpcodeUint32, memidx); break; } @@ -1640,11 +1682,16 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { ERROR_IF(data_count_ == kInvalidIndex, "memory.init requires data count section"); CHECK_RESULT(ReadIndex(&segment, "elem segment index")); - uint8_t reserved; - CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); - ERROR_UNLESS(reserved == 0, "reserved value must be 0"); - CALLBACK(OnMemoryInitExpr, segment); - CALLBACK(OnOpcodeUint32Uint32, segment, reserved); + Index memidx = 0; + if (!options_.features.multi_memory_enabled()) { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); + ERROR_UNLESS(reserved == 0, "reserved value must be 0"); + } else { + CHECK_RESULT(ReadMemidx(&memidx, "memory.init memidx")); + } + CALLBACK(OnMemoryInitExpr, segment, memidx); + CALLBACK(OnOpcodeUint32Uint32, segment, memidx); break; } @@ -1665,21 +1712,34 @@ Result BinaryReader::ReadFunctionBody(Offset end_offset) { } case Opcode::MemoryFill: { - uint8_t reserved; - CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); - ERROR_UNLESS(reserved == 0, "reserved value must be 0"); - CALLBACK(OnMemoryFillExpr); - CALLBACK(OnOpcodeUint32, reserved); + Index memidx = 0; + if (!options_.features.multi_memory_enabled()) { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "memory.fill reserved")); + ERROR_UNLESS(reserved == 0, "memory.fill reserved value must be 0"); + } else { + CHECK_RESULT(ReadMemidx(&memidx, "memory.fill memidx")); + } + CALLBACK(OnMemoryFillExpr, memidx); + CALLBACK(OnOpcodeUint32, memidx); break; } + case Opcode::MemoryCopy: { - uint8_t reserved; - CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); - ERROR_UNLESS(reserved == 0, "reserved value must be 0"); - CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); - ERROR_UNLESS(reserved == 0, "reserved value must be 0"); - CALLBACK(OnMemoryCopyExpr); - CALLBACK(OnOpcodeUint32Uint32, reserved, reserved); + Index srcmemidx = 0; + Index destmemidx = 0; + if (!options_.features.multi_memory_enabled()) { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); + ERROR_UNLESS(reserved == 0, "reserved value must be 0"); + CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); + ERROR_UNLESS(reserved == 0, "reserved value must be 0"); + } else { + CHECK_RESULT(ReadMemidx(&srcmemidx, "memory.copy srcmemidx")); + CHECK_RESULT(ReadMemidx(&destmemidx, "memory.copy destmemindex")); + } + CALLBACK(OnMemoryCopyExpr, srcmemidx, destmemidx); + CALLBACK(OnOpcodeUint32Uint32, srcmemidx, destmemidx); break; } diff --git a/src/binary-reader.h b/src/binary-reader.h index ff954d9d..a10fa395 100644 --- a/src/binary-reader.h +++ b/src/binary-reader.h @@ -251,18 +251,19 @@ class BinaryReaderDelegate { virtual Result OnI64ConstExpr(uint64_t value) = 0; virtual Result OnIfExpr(Type sig_type) = 0; virtual Result OnLoadExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) = 0; virtual Result OnLocalGetExpr(Index local_index) = 0; virtual Result OnLocalSetExpr(Index local_index) = 0; virtual Result OnLocalTeeExpr(Index local_index) = 0; virtual Result OnLoopExpr(Type sig_type) = 0; - virtual Result OnMemoryCopyExpr() = 0; + virtual Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) = 0; virtual Result OnDataDropExpr(Index segment_index) = 0; - virtual Result OnMemoryFillExpr() = 0; - virtual Result OnMemoryGrowExpr() = 0; - virtual Result OnMemoryInitExpr(Index segment_index) = 0; - virtual Result OnMemorySizeExpr() = 0; + virtual Result OnMemoryFillExpr(Index memidx) = 0; + virtual Result OnMemoryGrowExpr(Index memidx) = 0; + virtual Result OnMemoryInitExpr(Index segment_index, Index memidx) = 0; + virtual Result OnMemorySizeExpr(Index memidx) = 0; virtual Result OnTableCopyExpr(Index dst_index, Index src_index) = 0; virtual Result OnElemDropExpr(Index segment_index) = 0; virtual Result OnTableInitExpr(Index segment_index, Index table_index) = 0; @@ -282,6 +283,7 @@ class BinaryReaderDelegate { Index table_index) = 0; virtual Result OnSelectExpr(Index result_count, Type* result_types) = 0; virtual Result OnStoreExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) = 0; virtual Result OnThrowExpr(Index tag_index) = 0; diff --git a/src/binary-writer.cc b/src/binary-writer.cc index d78d98df..c3adfbf6 100644 --- a/src/binary-writer.cc +++ b/src/binary-writer.cc @@ -386,7 +386,13 @@ class BinaryWriter { template <typename T> void WriteLoadStoreExpr(const Func* func, const Expr* expr, const char* desc); template <typename T> - void WriteSimdLoadStoreLaneExpr(const Func* func, const Expr* expr, const char* desc); + void WriteMemoryLoadStoreExpr(const Func* func, + const Expr* expr, + const char* desc); + template <typename T> + void WriteSimdLoadStoreLaneExpr(const Func* func, + const Expr* expr, + const char* desc); void WriteExpr(const Func* func, const Expr* expr); void WriteExprList(const Func* func, const ExprList& exprs); void WriteInitExpr(const ExprList& expr); @@ -659,6 +665,24 @@ void BinaryWriter::WriteLoadStoreExpr(const Func* func, } template <typename T> +void BinaryWriter::WriteMemoryLoadStoreExpr(const Func* func, + const Expr* expr, + const char* desc) { + auto* typed_expr = cast<T>(expr); + WriteOpcode(stream_, typed_expr->opcode); + Address align = typed_expr->opcode.GetAlignment(typed_expr->align); + Index memidx = module_->GetMemoryIndex(typed_expr->memidx); + if (memidx != 0) { + stream_->WriteU8(log2_u32(align) | (1 << 6), "alignment"); + WriteU32Leb128(stream_, typed_expr->offset, desc); + WriteU32Leb128(stream_, memidx, "memidx"); + } else { + stream_->WriteU8(log2_u32(align), "alignment"); + WriteU32Leb128(stream_, typed_expr->offset, desc); + } +}; + +template <typename T> void BinaryWriter::WriteSimdLoadStoreLaneExpr(const Func* func, const Expr* expr, const char* desc) { @@ -828,7 +852,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { break; } case ExprType::Load: - WriteLoadStoreExpr<LoadExpr>(func, expr, "load offset"); + WriteMemoryLoadStoreExpr<LoadExpr>(func, expr, "load offset"); break; case ExprType::LocalGet: { Index index = GetLocalIndex(func, cast<LocalGetExpr>(expr)->var); @@ -854,11 +878,16 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { WriteExprList(func, cast<LoopExpr>(expr)->block.exprs); WriteOpcode(stream_, Opcode::End); break; - case ExprType::MemoryCopy: + case ExprType::MemoryCopy: { + Index srcmemidx = + module_->GetMemoryIndex(cast<MemoryCopyExpr>(expr)->srcmemidx); + Index destmemidx = + module_->GetMemoryIndex(cast<MemoryCopyExpr>(expr)->destmemidx); WriteOpcode(stream_, Opcode::MemoryCopy); - WriteU32Leb128(stream_, 0, "memory.copy reserved"); - WriteU32Leb128(stream_, 0, "memory.copy reserved"); + WriteU32Leb128(stream_, srcmemidx, "memory.copy srcmemidx"); + WriteU32Leb128(stream_, destmemidx, "memory.copy destmemidx"); break; + } case ExprType::DataDrop: { Index index = module_->GetDataSegmentIndex(cast<DataDropExpr>(expr)->var); @@ -867,27 +896,38 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { has_data_segment_instruction_ = true; break; } - case ExprType::MemoryFill: + case ExprType::MemoryFill: { + Index memidx = + module_->GetMemoryIndex(cast<MemoryFillExpr>(expr)->memidx); WriteOpcode(stream_, Opcode::MemoryFill); - WriteU32Leb128(stream_, 0, "memory.fill reserved"); + WriteU32Leb128(stream_, memidx, "memory.fill memidx"); break; - case ExprType::MemoryGrow: + } + case ExprType::MemoryGrow: { + Index memidx = + module_->GetMemoryIndex(cast<MemoryGrowExpr>(expr)->memidx); WriteOpcode(stream_, Opcode::MemoryGrow); - WriteU32Leb128(stream_, 0, "memory.grow reserved"); + WriteU32Leb128(stream_, memidx, "memory.grow memidx"); break; + } case ExprType::MemoryInit: { Index index = module_->GetDataSegmentIndex(cast<MemoryInitExpr>(expr)->var); + Index memidx = + module_->GetMemoryIndex(cast<MemoryInitExpr>(expr)->memidx); WriteOpcode(stream_, Opcode::MemoryInit); WriteU32Leb128(stream_, index, "memory.init segment"); - WriteU32Leb128(stream_, 0, "memory.init reserved"); + WriteU32Leb128(stream_, memidx, "memory.init memidx"); has_data_segment_instruction_ = true; break; } - case ExprType::MemorySize: + case ExprType::MemorySize: { + Index memidx = + module_->GetMemoryIndex(cast<MemorySizeExpr>(expr)->memidx); WriteOpcode(stream_, Opcode::MemorySize); - WriteU32Leb128(stream_, 0, "memory.size reserved"); + WriteU32Leb128(stream_, memidx, "memory.size memidx"); break; + } case ExprType::TableCopy: { auto* copy_expr = cast<TableCopyExpr>(expr); Index dst = module_->GetTableIndex(copy_expr->dst_table); @@ -989,7 +1029,7 @@ void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { break; } case ExprType::Store: - WriteLoadStoreExpr<StoreExpr>(func, expr, "store offset"); + WriteMemoryLoadStoreExpr<StoreExpr>(func, expr, "store offset"); break; case ExprType::Throw: WriteOpcode(stream_, Opcode::Throw); @@ -1591,7 +1631,13 @@ Result BinaryWriter::WriteModule() { uint8_t flags = segment->GetFlags(module_); stream_->WriteU8(flags, "segment flags"); if (!(flags & SegPassive)) { - assert(module_->GetMemoryIndex(segment->memory_var) == 0); + if (options_.features.multi_memory_enabled() && + (flags & SegExplicitIndex)) { + WriteU32Leb128(stream_, module_->GetMemoryIndex(segment->memory_var), + "memidx"); + } else { + assert(module_->GetMemoryIndex(segment->memory_var) == 0); + } WriteInitExpr(segment->offset); } WriteU32Leb128(stream_, segment->data.size(), "data segment size"); diff --git a/src/c-writer.cc b/src/c-writer.cc index df8c037b..d4381a6e 100644 --- a/src/c-writer.cc +++ b/src/c-writer.cc @@ -1001,7 +1001,6 @@ void CWriter::WriteMemories() { Write(Newline()); - assert(module_->memories.size() <= 1); Index memory_index = 0; for (const Memory* memory : module_->memories) { bool is_import = memory_index < module_->num_memory_imports; @@ -1069,11 +1068,15 @@ void CWriter::WriteDataInitializers() { } Write(Newline(), "static void init_memory(void) ", OpenBrace()); - if (memory && module_->num_memory_imports == 0) { - uint32_t max = - memory->page_limits.has_max ? memory->page_limits.max : 65536; - Write("wasm_rt_allocate_memory(", ExternalPtr(memory->name), ", ", - memory->page_limits.initial, ", ", max, ");", Newline()); + if (module_->memories.size() > module_->num_memory_imports) { + Index memory_idx = module_->num_memory_imports; + for (Index i = memory_idx; i < module_->memories.size(); i++) { + memory = module_->memories[i]; + uint32_t max = + memory->page_limits.has_max ? memory->page_limits.max : 65536; + Write("wasm_rt_allocate_memory(", ExternalPtr(memory->name), ", ", + memory->page_limits.initial, ", ", max, ");", Newline()); + } } data_segment_index = 0; for (const DataSegment* data_segment : module_->data_segments) { @@ -1613,8 +1616,8 @@ void CWriter::Write(const ExprList& exprs) { break; case ExprType::MemoryGrow: { - assert(module_->memories.size() == 1); - Memory* memory = module_->memories[0]; + Memory* memory = module_->memories[module_->GetMemoryIndex( + cast<MemoryGrowExpr>(&expr)->memidx)]; Write(StackVar(0), " = wasm_rt_grow_memory(", ExternalPtr(memory->name), ", ", StackVar(0), ");", Newline()); @@ -1622,8 +1625,8 @@ void CWriter::Write(const ExprList& exprs) { } case ExprType::MemorySize: { - assert(module_->memories.size() == 1); - Memory* memory = module_->memories[0]; + Memory* memory = module_->memories[module_->GetMemoryIndex( + cast<MemorySizeExpr>(&expr)->memidx)]; PushType(Type::I32); Write(StackVar(0), " = ", ExternalRef(memory->name), ".pages;", @@ -2119,8 +2122,7 @@ void CWriter::Write(const LoadExpr& expr) { WABT_UNREACHABLE; } - assert(module_->memories.size() == 1); - Memory* memory = module_->memories[0]; + Memory* memory = module_->memories[module_->GetMemoryIndex(expr.memidx)]; Type result_type = expr.opcode.GetResultType(); Write(StackVar(0, result_type), " = ", func, "(", ExternalPtr(memory->name), @@ -2149,8 +2151,7 @@ void CWriter::Write(const StoreExpr& expr) { WABT_UNREACHABLE; } - assert(module_->memories.size() == 1); - Memory* memory = module_->memories[0]; + Memory* memory = module_->memories[module_->GetMemoryIndex(expr.memidx)]; Write(func, "(", ExternalPtr(memory->name), ", (u64)(", StackVar(1), ")"); if (expr.offset != 0) diff --git a/src/feature.def b/src/feature.def index 238e8518..cecab3e6 100644 --- a/src/feature.def +++ b/src/feature.def @@ -36,3 +36,4 @@ WABT_FEATURE(reference_types, "reference-types", true, "Reference WABT_FEATURE(annotations, "annotations", false, "Custom annotation syntax") WABT_FEATURE(gc, "gc", false, "Garbage collection") WABT_FEATURE(memory64, "memory64", false, "64-bit memory") +WABT_FEATURE(multi_memory, "multi-memory", false, "Multi-memory") diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc index eaae9f1b..0cec0c21 100644 --- a/src/interp/binary-reader-interp.cc +++ b/src/interp/binary-reader-interp.cc @@ -196,19 +196,20 @@ class BinaryReaderInterp : public BinaryReaderNop { Result OnI64ConstExpr(uint64_t value) override; Result OnIfExpr(Type sig_type) override; Result OnLoadExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override; Result OnLocalGetExpr(Index local_index) override; Result OnLocalSetExpr(Index local_index) override; Result OnLocalTeeExpr(Index local_index) override; Result OnLoopExpr(Type sig_type) override; - Result OnMemoryCopyExpr() override; + Result OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) override; Result OnDataDropExpr(Index segment_index) override; - Result OnMemoryGrowExpr() override; - Result OnMemoryFillExpr() override; - Result OnMemoryInitExpr(Index segment_index) override; - Result OnMemorySizeExpr() override; - Result OnRefFuncExpr(Index type_index) override; + Result OnMemoryGrowExpr(Index memidx) override; + Result OnMemoryFillExpr(Index memidx) override; + Result OnMemoryInitExpr(Index segment_index, Index memidx) override; + Result OnMemorySizeExpr(Index memidx) override; + Result OnRefFuncExpr(Index func_index) override; Result OnRefNullExpr(Type type) override; Result OnRefIsNullExpr() override; Result OnNopExpr() override; @@ -216,6 +217,7 @@ class BinaryReaderInterp : public BinaryReaderNop { Result OnReturnExpr() override; Result OnSelectExpr(Index result_count, Type* result_types) override; Result OnStoreExpr(Opcode opcode, + Index memidx, Address alignment_log2, Address offset) override; Result OnUnaryExpr(Opcode opcode) override; @@ -1331,30 +1333,34 @@ Result BinaryReaderInterp::OnLocalTeeExpr(Index local_index) { } Result BinaryReaderInterp::OnLoadExpr(Opcode opcode, + Index memidx, Address align_log2, Address offset) { - CHECK_RESULT(validator_.OnLoad(loc, opcode, GetAlignment(align_log2))); - istream_.Emit(opcode, kMemoryIndex0, offset); + CHECK_RESULT( + validator_.OnLoad(loc, opcode, Var(memidx), GetAlignment(align_log2))); + istream_.Emit(opcode, memidx, offset); return Result::Ok; } Result BinaryReaderInterp::OnStoreExpr(Opcode opcode, + Index memidx, Address align_log2, Address offset) { - CHECK_RESULT(validator_.OnStore(loc, opcode, GetAlignment(align_log2))); - istream_.Emit(opcode, kMemoryIndex0, offset); + CHECK_RESULT( + validator_.OnStore(loc, opcode, Var(memidx), GetAlignment(align_log2))); + istream_.Emit(opcode, memidx, offset); return Result::Ok; } -Result BinaryReaderInterp::OnMemoryGrowExpr() { - CHECK_RESULT(validator_.OnMemoryGrow(loc)); - istream_.Emit(Opcode::MemoryGrow, kMemoryIndex0); +Result BinaryReaderInterp::OnMemoryGrowExpr(Index memidx) { + CHECK_RESULT(validator_.OnMemoryGrow(loc, Var(memidx))); + istream_.Emit(Opcode::MemoryGrow, memidx); return Result::Ok; } -Result BinaryReaderInterp::OnMemorySizeExpr() { - CHECK_RESULT(validator_.OnMemorySize(loc)); - istream_.Emit(Opcode::MemorySize, kMemoryIndex0); +Result BinaryReaderInterp::OnMemorySizeExpr(Index memidx) { + CHECK_RESULT(validator_.OnMemorySize(loc, Var(memidx))); + istream_.Emit(Opcode::MemorySize, memidx); return Result::Ok; } @@ -1447,9 +1453,9 @@ Result BinaryReaderInterp::OnAtomicNotifyExpr(Opcode opcode, return Result::Ok; } -Result BinaryReaderInterp::OnMemoryCopyExpr() { - CHECK_RESULT(validator_.OnMemoryCopy(loc)); - istream_.Emit(Opcode::MemoryCopy, kMemoryIndex0, kMemoryIndex0); +Result BinaryReaderInterp::OnMemoryCopyExpr(Index srcmemidx, Index destmemidx) { + CHECK_RESULT(validator_.OnMemoryCopy(loc, Var(srcmemidx), Var(destmemidx))); + istream_.Emit(Opcode::MemoryCopy, srcmemidx, destmemidx); return Result::Ok; } @@ -1459,15 +1465,15 @@ Result BinaryReaderInterp::OnDataDropExpr(Index segment_index) { return Result::Ok; } -Result BinaryReaderInterp::OnMemoryFillExpr() { - CHECK_RESULT(validator_.OnMemoryFill(loc)); - istream_.Emit(Opcode::MemoryFill, kMemoryIndex0); +Result BinaryReaderInterp::OnMemoryFillExpr(Index memidx) { + CHECK_RESULT(validator_.OnMemoryFill(loc, Var(memidx))); + istream_.Emit(Opcode::MemoryFill, memidx); return Result::Ok; } -Result BinaryReaderInterp::OnMemoryInitExpr(Index segment_index) { - CHECK_RESULT(validator_.OnMemoryInit(loc, Var(segment_index))); - istream_.Emit(Opcode::MemoryInit, kMemoryIndex0, segment_index); +Result BinaryReaderInterp::OnMemoryInitExpr(Index segment_index, Index memidx) { + CHECK_RESULT(validator_.OnMemoryInit(loc, Var(segment_index), Var(memidx))); + istream_.Emit(Opcode::MemoryInit, memidx, segment_index); return Result::Ok; } @@ -418,15 +418,40 @@ class ExprMixin : public Expr { explicit ExprMixin(const Location& loc = Location()) : Expr(TypeEnum, loc) {} }; +template <ExprType TypeEnum> +class MemoryExpr : public ExprMixin<TypeEnum> { + public: + MemoryExpr(Var memidx, const Location& loc = Location()) + : ExprMixin<TypeEnum>(loc), memidx(memidx) {} + + Var memidx; +}; + +template <ExprType TypeEnum> +class MemoryBinaryExpr : public ExprMixin<TypeEnum> { + public: + MemoryBinaryExpr(Var srcmemidx, + Var destmemidx, + const Location& loc = Location()) + : ExprMixin<TypeEnum>(loc), + srcmemidx(srcmemidx), + destmemidx(destmemidx) {} + + Var srcmemidx; + Var destmemidx; +}; + typedef ExprMixin<ExprType::Drop> DropExpr; -typedef ExprMixin<ExprType::MemoryGrow> MemoryGrowExpr; -typedef ExprMixin<ExprType::MemorySize> MemorySizeExpr; -typedef ExprMixin<ExprType::MemoryCopy> MemoryCopyExpr; -typedef ExprMixin<ExprType::MemoryFill> MemoryFillExpr; typedef ExprMixin<ExprType::Nop> NopExpr; typedef ExprMixin<ExprType::Return> ReturnExpr; typedef ExprMixin<ExprType::Unreachable> UnreachableExpr; +typedef MemoryExpr<ExprType::MemoryGrow> MemoryGrowExpr; +typedef MemoryExpr<ExprType::MemorySize> MemorySizeExpr; +typedef MemoryExpr<ExprType::MemoryFill> MemoryFillExpr; + +typedef MemoryBinaryExpr<ExprType::MemoryCopy> MemoryCopyExpr; + template <ExprType TypeEnum> class RefTypeExpr : public ExprMixin<TypeEnum> { public: @@ -515,6 +540,15 @@ class VarExpr : public ExprMixin<TypeEnum> { Var var; }; +template <ExprType TypeEnum> +class MemoryVarExpr : public MemoryExpr<TypeEnum> { + public: + MemoryVarExpr(const Var& var, Var memidx, const Location& loc = Location()) + : MemoryExpr<TypeEnum>(memidx, loc), var(var) {} + + Var var; +}; + typedef VarExpr<ExprType::Br> BrExpr; typedef VarExpr<ExprType::BrIf> BrIfExpr; typedef VarExpr<ExprType::Call> CallExpr; @@ -528,7 +562,6 @@ typedef VarExpr<ExprType::ReturnCall> ReturnCallExpr; typedef VarExpr<ExprType::Throw> ThrowExpr; typedef VarExpr<ExprType::Rethrow> RethrowExpr; -typedef VarExpr<ExprType::MemoryInit> MemoryInitExpr; typedef VarExpr<ExprType::DataDrop> DataDropExpr; typedef VarExpr<ExprType::ElemDrop> ElemDropExpr; typedef VarExpr<ExprType::TableGet> TableGetExpr; @@ -537,6 +570,8 @@ typedef VarExpr<ExprType::TableGrow> TableGrowExpr; typedef VarExpr<ExprType::TableSize> TableSizeExpr; typedef VarExpr<ExprType::TableFill> TableFillExpr; +typedef MemoryVarExpr<ExprType::MemoryInit> MemoryInitExpr; + class SelectExpr : public ExprMixin<ExprType::Select> { public: SelectExpr(TypeVector type, const Location& loc = Location()) @@ -664,8 +699,27 @@ class LoadStoreExpr : public ExprMixin<TypeEnum> { Address offset; }; -typedef LoadStoreExpr<ExprType::Load> LoadExpr; -typedef LoadStoreExpr<ExprType::Store> StoreExpr; +template <ExprType TypeEnum> +class MemoryLoadStoreExpr : public MemoryExpr<TypeEnum> { + public: + MemoryLoadStoreExpr(Opcode opcode, + Var memidx, + Address align, + Address offset, + const Location& loc = Location()) + : MemoryExpr<TypeEnum>(memidx, loc), + opcode(opcode), + align(align), + offset(offset) {} + + Opcode opcode; + Address align; + Address offset; +}; + +typedef MemoryLoadStoreExpr<ExprType::Load> LoadExpr; +typedef MemoryLoadStoreExpr<ExprType::Store> StoreExpr; + typedef LoadStoreExpr<ExprType::AtomicLoad> AtomicLoadExpr; typedef LoadStoreExpr<ExprType::AtomicStore> AtomicStoreExpr; typedef LoadStoreExpr<ExprType::AtomicRmw> AtomicRmwExpr; diff --git a/src/resolve-names.cc b/src/resolve-names.cc index abd554ff..4c4c1495 100644 --- a/src/resolve-names.cc +++ b/src/resolve-names.cc @@ -51,13 +51,18 @@ class NameResolver : public ExprVisitor::DelegateNop { Result OnGlobalSetExpr(GlobalSetExpr*) override; Result BeginIfExpr(IfExpr*) override; Result EndIfExpr(IfExpr*) override; + Result OnLoadExpr(LoadExpr*) override; Result OnLocalGetExpr(LocalGetExpr*) override; Result OnLocalSetExpr(LocalSetExpr*) override; Result OnLocalTeeExpr(LocalTeeExpr*) override; Result BeginLoopExpr(LoopExpr*) override; Result EndLoopExpr(LoopExpr*) override; + Result OnMemoryCopyExpr(MemoryCopyExpr*) override; Result OnDataDropExpr(DataDropExpr*) override; + Result OnMemoryFillExpr(MemoryFillExpr*) override; + Result OnMemoryGrowExpr(MemoryGrowExpr*) override; Result OnMemoryInitExpr(MemoryInitExpr*) override; + Result OnMemorySizeExpr(MemorySizeExpr*) override; Result OnElemDropExpr(ElemDropExpr*) override; Result OnTableCopyExpr(TableCopyExpr*) override; Result OnTableInitExpr(TableInitExpr*) override; @@ -67,6 +72,7 @@ class NameResolver : public ExprVisitor::DelegateNop { Result OnTableSizeExpr(TableSizeExpr*) override; Result OnTableFillExpr(TableFillExpr*) override; Result OnRefFuncExpr(RefFuncExpr*) override; + Result OnStoreExpr(StoreExpr*) override; Result BeginTryExpr(TryExpr*) override; Result EndTryExpr(TryExpr*) override; Result OnThrowExpr(ThrowExpr*) override; @@ -321,6 +327,11 @@ Result NameResolver::EndIfExpr(IfExpr* expr) { return Result::Ok; } +Result NameResolver::OnLoadExpr(LoadExpr* expr) { + ResolveMemoryVar(&expr->memidx); + return Result::Ok; +} + Result NameResolver::OnLocalGetExpr(LocalGetExpr* expr) { ResolveLocalVar(&expr->var); return Result::Ok; @@ -336,13 +347,35 @@ Result NameResolver::OnLocalTeeExpr(LocalTeeExpr* expr) { return Result::Ok; } +Result NameResolver::OnMemoryCopyExpr(MemoryCopyExpr* expr) { + ResolveMemoryVar(&expr->srcmemidx); + ResolveMemoryVar(&expr->destmemidx); + return Result::Ok; +} + Result NameResolver::OnDataDropExpr(DataDropExpr* expr) { ResolveDataSegmentVar(&expr->var); return Result::Ok; } +Result NameResolver::OnMemoryFillExpr(MemoryFillExpr* expr) { + ResolveMemoryVar(&expr->memidx); + return Result::Ok; +} + +Result NameResolver::OnMemoryGrowExpr(MemoryGrowExpr* expr) { + ResolveMemoryVar(&expr->memidx); + return Result::Ok; +} + Result NameResolver::OnMemoryInitExpr(MemoryInitExpr* expr) { ResolveDataSegmentVar(&expr->var); + ResolveMemoryVar(&expr->memidx); + return Result::Ok; +} + +Result NameResolver::OnMemorySizeExpr(MemorySizeExpr* expr) { + ResolveMemoryVar(&expr->memidx); return Result::Ok; } @@ -393,6 +426,11 @@ Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) { return Result::Ok; } +Result NameResolver::OnStoreExpr(StoreExpr* expr) { + ResolveMemoryVar(&expr->memidx); + return Result::Ok; +} + Result NameResolver::BeginTryExpr(TryExpr* expr) { PushLabel(expr->block.label); ResolveBlockDeclarationVar(&expr->block.decl); diff --git a/src/shared-validator.cc b/src/shared-validator.cc index 071a1c0f..2a5a4a8e 100644 --- a/src/shared-validator.cc +++ b/src/shared-validator.cc @@ -135,7 +135,7 @@ Result SharedValidator::OnTable(const Location& loc, Result SharedValidator::OnMemory(const Location& loc, const Limits& limits) { Result result = Result::Ok; - if (memories_.size() > 0) { + if (memories_.size() > 0 && !options_.features.multi_memory_enabled()) { result |= PrintError(loc, "only one memory block allowed"); } result |= CheckLimits( @@ -903,11 +903,12 @@ Result SharedValidator::OnIf(const Location& loc, Type sig_type) { Result SharedValidator::OnLoad(const Location& loc, Opcode opcode, + Var memidx, Address alignment) { Result result = Result::Ok; MemoryType mt; expr_loc_ = &loc; - result |= CheckMemoryIndex(Var(0, loc), &mt); + result |= CheckMemoryIndex(memidx, &mt); result |= CheckAlign(loc, alignment, opcode.GetMemorySize()); result |= typechecker_.OnLoad(opcode, mt.limits); return result; @@ -974,16 +975,19 @@ Result SharedValidator::OnLoop(const Location& loc, Type sig_type) { return result; } -Result SharedValidator::OnMemoryCopy(const Location& loc) { +Result SharedValidator::OnMemoryCopy(const Location& loc, + Var srcmemidx, + Var destmemidx) { Result result = Result::Ok; MemoryType mt; expr_loc_ = &loc; - result |= CheckMemoryIndex(Var(0, loc), &mt); + result |= CheckMemoryIndex(srcmemidx, &mt); + result |= CheckMemoryIndex(destmemidx, &mt); result |= typechecker_.OnMemoryCopy(mt.limits); return result; } -Result SharedValidator::OnMemoryFill(const Location& loc) { +Result SharedValidator::OnMemoryFill(const Location& loc, Var memidx) { Result result = Result::Ok; MemoryType mt; expr_loc_ = &loc; @@ -992,30 +996,32 @@ Result SharedValidator::OnMemoryFill(const Location& loc) { return result; } -Result SharedValidator::OnMemoryGrow(const Location& loc) { +Result SharedValidator::OnMemoryGrow(const Location& loc, Var memidx) { Result result = Result::Ok; MemoryType mt; expr_loc_ = &loc; - result |= CheckMemoryIndex(Var(0, loc), &mt); + result |= CheckMemoryIndex(memidx, &mt); result |= typechecker_.OnMemoryGrow(mt.limits); return result; } -Result SharedValidator::OnMemoryInit(const Location& loc, Var segment_var) { +Result SharedValidator::OnMemoryInit(const Location& loc, + Var segment_var, + Var memidx) { Result result = Result::Ok; MemoryType mt; expr_loc_ = &loc; - result |= CheckMemoryIndex(Var(0, loc), &mt); + result |= CheckMemoryIndex(memidx, &mt); result |= CheckDataSegmentIndex(segment_var); result |= typechecker_.OnMemoryInit(segment_var.index(), mt.limits); return result; } -Result SharedValidator::OnMemorySize(const Location& loc) { +Result SharedValidator::OnMemorySize(const Location& loc, Var memidx) { Result result = Result::Ok; MemoryType mt; expr_loc_ = &loc; - result |= CheckMemoryIndex(Var(0, loc), &mt); + result |= CheckMemoryIndex(memidx, &mt); result |= typechecker_.OnMemorySize(mt.limits); return result; } @@ -1144,11 +1150,12 @@ Result SharedValidator::OnSimdShuffleOp(const Location& loc, Result SharedValidator::OnStore(const Location& loc, Opcode opcode, + Var memidx, Address alignment) { Result result = Result::Ok; MemoryType mt; expr_loc_ = &loc; - result |= CheckMemoryIndex(Var(0, loc), &mt); + result |= CheckMemoryIndex(memidx, &mt); result |= CheckAlign(loc, alignment, opcode.GetMemorySize()); result |= typechecker_.OnStore(opcode, mt.limits); return result; diff --git a/src/shared-validator.h b/src/shared-validator.h index 3bc02ff3..9c28af74 100644 --- a/src/shared-validator.h +++ b/src/shared-validator.h @@ -142,18 +142,18 @@ class SharedValidator { Result OnGlobalGet(const Location&, Var); Result OnGlobalSet(const Location&, Var); Result OnIf(const Location&, Type sig_type); - Result OnLoad(const Location&, Opcode, Address align); + Result OnLoad(const Location&, Opcode, Var memidx, Address align); Result OnLoadSplat(const Location&, Opcode, Address align); Result OnLoadZero(const Location&, Opcode, Address align); Result OnLocalGet(const Location&, Var); Result OnLocalSet(const Location&, Var); Result OnLocalTee(const Location&, Var); Result OnLoop(const Location&, Type sig_type); - Result OnMemoryCopy(const Location&); - Result OnMemoryFill(const Location&); - Result OnMemoryGrow(const Location&); - Result OnMemoryInit(const Location&, Var segment_var); - Result OnMemorySize(const Location&); + Result OnMemoryCopy(const Location&, Var srcmemidx, Var destmemidx); + Result OnMemoryFill(const Location&, Var memidx); + Result OnMemoryGrow(const Location&, Var memidx); + Result OnMemoryInit(const Location&, Var segment_var, Var memidx); + Result OnMemorySize(const Location&, Var memidx); Result OnNop(const Location&); Result OnRefFunc(const Location&, Var func_var); Result OnRefIsNull(const Location&); @@ -167,7 +167,7 @@ class SharedValidator { Result OnSimdLoadLane(const Location&, Opcode, Address align, uint64_t lane_idx); Result OnSimdStoreLane(const Location&, Opcode, Address align, uint64_t lane_idx); Result OnSimdShuffleOp(const Location&, Opcode, v128 lane_idx); - Result OnStore(const Location&, Opcode, Address align); + Result OnStore(const Location&, Opcode, Var memidx, Address align); Result OnTableCopy(const Location&, Var dst_var, Var src_var); Result OnTableFill(const Location&, Var table_var); Result OnTableGet(const Location&, Var table_var); diff --git a/src/validator.cc b/src/validator.cc index 672f698b..75c06211 100644 --- a/src/validator.cc +++ b/src/validator.cc @@ -334,7 +334,7 @@ Result Validator::EndIfExpr(IfExpr* expr) { } Result Validator::OnLoadExpr(LoadExpr* expr) { - result_ |= validator_.OnLoad(expr->loc, expr->opcode, + result_ |= validator_.OnLoad(expr->loc, expr->opcode, expr->memidx, expr->opcode.GetAlignment(expr->align)); return Result::Ok; } @@ -365,7 +365,8 @@ Result Validator::EndLoopExpr(LoopExpr* expr) { } Result Validator::OnMemoryCopyExpr(MemoryCopyExpr* expr) { - result_ |= validator_.OnMemoryCopy(expr->loc); + result_ |= + validator_.OnMemoryCopy(expr->loc, expr->srcmemidx, expr->destmemidx); return Result::Ok; } @@ -375,22 +376,22 @@ Result Validator::OnDataDropExpr(DataDropExpr* expr) { } Result Validator::OnMemoryFillExpr(MemoryFillExpr* expr) { - result_ |= validator_.OnMemoryFill(expr->loc); + result_ |= validator_.OnMemoryFill(expr->loc, expr->memidx); return Result::Ok; } Result Validator::OnMemoryGrowExpr(MemoryGrowExpr* expr) { - result_ |= validator_.OnMemoryGrow(expr->loc); + result_ |= validator_.OnMemoryGrow(expr->loc, expr->memidx); return Result::Ok; } Result Validator::OnMemoryInitExpr(MemoryInitExpr* expr) { - result_ |= validator_.OnMemoryInit(expr->loc, expr->var); + result_ |= validator_.OnMemoryInit(expr->loc, expr->var, expr->memidx); return Result::Ok; } Result Validator::OnMemorySizeExpr(MemorySizeExpr* expr) { - result_ |= validator_.OnMemorySize(expr->loc); + result_ |= validator_.OnMemorySize(expr->loc, expr->memidx); return Result::Ok; } @@ -484,7 +485,7 @@ Result Validator::OnSelectExpr(SelectExpr* expr) { } Result Validator::OnStoreExpr(StoreExpr* expr) { - result_ |= validator_.OnStore(expr->loc, expr->opcode, + result_ |= validator_.OnStore(expr->loc, expr->opcode, expr->memidx, expr->opcode.GetAlignment(expr->align)); return Result::Ok; } diff --git a/src/wast-parser.cc b/src/wast-parser.cc index d12cbc44..79436fc1 100644 --- a/src/wast-parser.cc +++ b/src/wast-parser.cc @@ -1024,6 +1024,27 @@ bool WastParser::ParseAlignOpt(Address* out_align) { } } +Result WastParser::ParseMemidx(Location loc, Var* out_memidx) { + WABT_TRACE(ParseMemidx); + if (PeekMatchLpar(TokenType::Memory)) { + if (!options_->features.multi_memory_enabled()) { + Error(loc, "Specifying memory variable is not allowed"); + return Result::Error; + } + EXPECT(Lpar); + EXPECT(Memory); + CHECK_RESULT(ParseVar(out_memidx)); + EXPECT(Rpar); + } else { + if (ParseVarOpt(out_memidx, Var(0, loc)) && + !options_->features.multi_memory_enabled()) { + Error(loc, "Specifying memory variable is not allowed"); + return Result::Error; + } + } + return Result::Ok; +} + Result WastParser::ParseLimitsIndex(Limits* out_limits) { WABT_TRACE(ParseLimitsIndex); @@ -1861,6 +1882,34 @@ Result WastParser::ParsePlainInstrVar(Location loc, } template <typename T> +Result WastParser::ParseMemoryInstrVar(Location loc, + std::unique_ptr<Expr>* out_expr) { + Var memidx; + Var var; + if (PeekMatchLpar(TokenType::Memory)) { + if (!options_->features.multi_memory_enabled()) { + Error(loc, "Specifying memory variable is not allowed"); + return Result::Error; + } + CHECK_RESULT(ParseMemidx(loc, &memidx)); + CHECK_RESULT(ParseVar(&var)); + out_expr->reset(new T(var, memidx, loc)); + } else { + CHECK_RESULT(ParseVar(&memidx)); + if (ParseVarOpt(&var, Var(0, loc))) { + if (!options_->features.multi_memory_enabled()) { + Error(loc, "Specifiying memory variable is not allowed"); + return Result::Error; + } + out_expr->reset(new T(var, memidx, loc)); + } else { + out_expr->reset(new T(memidx, var, loc)); + } + } + return Result::Ok; +} + +template <typename T> Result WastParser::ParsePlainLoadStoreInstr(Location loc, Token token, std::unique_ptr<Expr>* out_expr) { @@ -1873,6 +1922,41 @@ Result WastParser::ParsePlainLoadStoreInstr(Location loc, return Result::Ok; } +template <typename T> +Result WastParser::ParseMemoryLoadStoreInstr(Location loc, + Token token, + std::unique_ptr<Expr>* out_expr) { + Opcode opcode = token.opcode(); + Var memidx; + Address offset; + Address align; + CHECK_RESULT(ParseMemidx(loc, &memidx)); + ParseOffsetOpt(&offset); + ParseAlignOpt(&align); + out_expr->reset(new T(opcode, memidx, align, offset, loc)); + return Result::Ok; +} + +template <typename T> +Result WastParser::ParseMemoryExpr(Location loc, + std::unique_ptr<Expr>* out_expr) { + Var memidx; + CHECK_RESULT(ParseMemidx(loc, &memidx)); + out_expr->reset(new T(memidx, loc)); + return Result::Ok; +} + +template <typename T> +Result WastParser::ParseMemoryBinaryExpr(Location loc, + std::unique_ptr<Expr>* out_expr) { + Var srcmemidx; + Var destmemidx; + CHECK_RESULT(ParseMemidx(loc, &srcmemidx)); + CHECK_RESULT(ParseMemidx(loc, &destmemidx)); + out_expr->reset(new T(srcmemidx, destmemidx, loc)); + return Result::Ok; +} + Result WastParser::ParseSimdLane(Location loc, uint64_t* lane_idx) { if (!PeekMatch(TokenType::Nat) && !PeekMatch(TokenType::Int)) { return ErrorExpected({"a natural number in range [0, 32)"}); @@ -2019,12 +2103,12 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { case TokenType::Load: CHECK_RESULT( - ParsePlainLoadStoreInstr<LoadExpr>(loc, Consume(), out_expr)); + ParseMemoryLoadStoreInstr<LoadExpr>(loc, Consume(), out_expr)); break; case TokenType::Store: CHECK_RESULT( - ParsePlainLoadStoreInstr<StoreExpr>(loc, Consume(), out_expr)); + ParseMemoryLoadStoreInstr<StoreExpr>(loc, Consume(), out_expr)); break; case TokenType::Const: { @@ -2061,12 +2145,12 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { case TokenType::MemoryCopy: ErrorUnlessOpcodeEnabled(Consume()); - out_expr->reset(new MemoryCopyExpr(loc)); + CHECK_RESULT(ParseMemoryBinaryExpr<MemoryCopyExpr>(loc, out_expr)); break; case TokenType::MemoryFill: ErrorUnlessOpcodeEnabled(Consume()); - out_expr->reset(new MemoryFillExpr(loc)); + CHECK_RESULT(ParseMemoryExpr<MemoryFillExpr>(loc, out_expr)); break; case TokenType::DataDrop: @@ -2076,17 +2160,17 @@ Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) { case TokenType::MemoryInit: ErrorUnlessOpcodeEnabled(Consume()); - CHECK_RESULT(ParsePlainInstrVar<MemoryInitExpr>(loc, out_expr)); + CHECK_RESULT(ParseMemoryInstrVar<MemoryInitExpr>(loc, out_expr)); break; case TokenType::MemorySize: Consume(); - out_expr->reset(new MemorySizeExpr(loc)); + CHECK_RESULT(ParseMemoryExpr<MemorySizeExpr>(loc, out_expr)); break; case TokenType::MemoryGrow: Consume(); - out_expr->reset(new MemoryGrowExpr(loc)); + CHECK_RESULT(ParseMemoryExpr<MemoryGrowExpr>(loc, out_expr)); break; case TokenType::TableCopy: { diff --git a/src/wast-parser.h b/src/wast-parser.h index 1d304484..00285d31 100644 --- a/src/wast-parser.h +++ b/src/wast-parser.h @@ -143,6 +143,7 @@ class WastParser { Result ParseQuotedText(std::string* text); bool ParseOffsetOpt(Address* offset); bool ParseAlignOpt(Address* align); + Result ParseMemidx(Location loc, Var* memidx); Result ParseLimitsIndex(Limits*); Result ParseLimits(Limits*); Result ParseNat(uint64_t*, bool is_64); @@ -203,7 +204,15 @@ class WastParser { template <typename T> Result ParsePlainInstrVar(Location, std::unique_ptr<Expr>*); template <typename T> + Result ParseMemoryInstrVar(Location, std::unique_ptr<Expr>*); + template <typename T> Result ParsePlainLoadStoreInstr(Location, Token, std::unique_ptr<Expr>*); + template <typename T> + Result ParseMemoryLoadStoreInstr(Location, Token, std::unique_ptr<Expr>*); + template <typename T> + Result ParseMemoryExpr(Location, std::unique_ptr<Expr>*); + template <typename T> + Result ParseMemoryBinaryExpr(Location, std::unique_ptr<Expr>*); Result ParseSimdLane(Location, uint64_t*); Result ParseCommandList(Script*, CommandPtrVector*); diff --git a/src/wat-writer.cc b/src/wat-writer.cc index 4f40fd2a..531cb5b9 100644 --- a/src/wat-writer.cc +++ b/src/wat-writer.cc @@ -122,6 +122,10 @@ class WatWriter : ModuleContext { void WriteQuotedString(string_view str, NextChar next_char); void WriteVar(const Var& var, NextChar next_char); void WriteVarUnlessZero(const Var& var, NextChar next_char); + void WriteMemoryVarUnlessZero(const Var& memidx, NextChar next_char); + void WriteTwoMemoryVarsUnlessBothZero(const Var& srcmemidx, + const Var& destmemidx, + NextChar next_char); void WriteBrVar(const Var& var, NextChar next_char); void WriteRefKind(Type type, NextChar next_char); void WriteType(Type type, NextChar next_char); @@ -135,6 +139,8 @@ class WatWriter : ModuleContext { void WriteExpr(const Expr* expr); template <typename T> void WriteLoadStoreExpr(const Expr* expr); + template <typename T> + void WriteMemoryLoadStoreExpr(const Expr* expr); void WriteExprList(const ExprList& exprs); void WriteInitExpr(const ExprList& expr); template <typename T> @@ -375,6 +381,27 @@ void WatWriter::WriteVarUnlessZero(const Var& var, NextChar next_char) { } } +void WatWriter::WriteMemoryVarUnlessZero(const Var& memidx, + NextChar next_char) { + if (module.GetMemoryIndex(memidx) != 0) { + WriteVar(memidx, next_char); + } else { + next_char_ = next_char; + } +} + +void WatWriter::WriteTwoMemoryVarsUnlessBothZero(const Var& srcmemidx, + const Var& destmemidx, + NextChar next_char) { + if (module.GetMemoryIndex(srcmemidx) != 0 || + module.GetMemoryIndex(destmemidx) != 0) { + WriteVar(srcmemidx, NextChar::Space); + WriteVar(destmemidx, next_char); + } else { + next_char_ = next_char; + } +} + void WatWriter::WriteBrVar(const Var& var, NextChar next_char) { if (var.is_index()) { if (var.index() < GetLabelStackSize()) { @@ -504,6 +531,20 @@ void WatWriter::WriteLoadStoreExpr(const Expr* expr) { WriteNewline(NO_FORCE_NEWLINE); } +template <typename T> +void WatWriter::WriteMemoryLoadStoreExpr(const Expr* expr) { + auto typed_expr = cast<T>(expr); + WritePutsSpace(typed_expr->opcode.GetName()); + WriteMemoryVarUnlessZero(typed_expr->memidx, NextChar::Space); + if (typed_expr->offset) { + Writef("offset=%" PRIaddress, typed_expr->offset); + } + if (!typed_expr->opcode.IsNaturallyAligned(typed_expr->align)) { + Writef("align=%" PRIaddress, typed_expr->align); + } + WriteNewline(NO_FORCE_NEWLINE); +} + class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate { public: explicit ExprVisitorDelegate(WatWriter* writer) : writer_(writer) {} @@ -695,7 +736,7 @@ Result WatWriter::ExprVisitorDelegate::EndIfExpr(IfExpr* expr) { } Result WatWriter::ExprVisitorDelegate::OnLoadExpr(LoadExpr* expr) { - writer_->WriteLoadStoreExpr<LoadExpr>(expr); + writer_->WriteMemoryLoadStoreExpr<LoadExpr>(expr); return Result::Ok; } @@ -729,7 +770,10 @@ Result WatWriter::ExprVisitorDelegate::EndLoopExpr(LoopExpr* expr) { } Result WatWriter::ExprVisitorDelegate::OnMemoryCopyExpr(MemoryCopyExpr* expr) { - writer_->WritePutsNewline(Opcode::MemoryCopy_Opcode.GetName()); + writer_->WritePutsSpace(Opcode::MemoryCopy_Opcode.GetName()); + writer_->WriteTwoMemoryVarsUnlessBothZero(expr->srcmemidx, expr->destmemidx, + NextChar::Space); + writer_->WriteNewline(NO_FORCE_NEWLINE); return Result::Ok; } @@ -740,23 +784,31 @@ Result WatWriter::ExprVisitorDelegate::OnDataDropExpr(DataDropExpr* expr) { } Result WatWriter::ExprVisitorDelegate::OnMemoryFillExpr(MemoryFillExpr* expr) { - writer_->WritePutsNewline(Opcode::MemoryFill_Opcode.GetName()); + writer_->WritePutsSpace(Opcode::MemoryFill_Opcode.GetName()); + writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space); + writer_->WriteNewline(NO_FORCE_NEWLINE); return Result::Ok; } Result WatWriter::ExprVisitorDelegate::OnMemoryGrowExpr(MemoryGrowExpr* expr) { - writer_->WritePutsNewline(Opcode::MemoryGrow_Opcode.GetName()); + writer_->WritePutsSpace(Opcode::MemoryGrow_Opcode.GetName()); + writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space); + writer_->WriteNewline(NO_FORCE_NEWLINE); return Result::Ok; } Result WatWriter::ExprVisitorDelegate::OnMemorySizeExpr(MemorySizeExpr* expr) { - writer_->WritePutsNewline(Opcode::MemorySize_Opcode.GetName()); + writer_->WritePutsSpace(Opcode::MemorySize_Opcode.GetName()); + writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space); + writer_->WriteNewline(NO_FORCE_NEWLINE); return Result::Ok; } Result WatWriter::ExprVisitorDelegate::OnMemoryInitExpr(MemoryInitExpr* expr) { writer_->WritePutsSpace(Opcode::MemoryInit_Opcode.GetName()); - writer_->WriteVar(expr->var, NextChar::Newline); + writer_->WriteVar(expr->var, NextChar::Space); + writer_->WriteMemoryVarUnlessZero(expr->memidx, NextChar::Space); + writer_->WriteNewline(NO_FORCE_NEWLINE); return Result::Ok; } @@ -865,7 +917,7 @@ Result WatWriter::ExprVisitorDelegate::OnSelectExpr(SelectExpr* expr) { } Result WatWriter::ExprVisitorDelegate::OnStoreExpr(StoreExpr* expr) { - writer_->WriteLoadStoreExpr<StoreExpr>(expr); + writer_->WriteMemoryLoadStoreExpr<StoreExpr>(expr); return Result::Ok; } @@ -1423,6 +1475,7 @@ void WatWriter::WriteDataSegment(const DataSegment& segment) { WriteOpenSpace("data"); WriteNameOrIndex(segment.name, data_segment_index_, NextChar::Space); if (segment.kind != SegmentKind::Passive) { + WriteMemoryVarUnlessZero(segment.memory_var, NextChar::Space); WriteInitExpr(segment.offset); } WriteQuotedData(segment.data.data(), segment.data.size()); |