Repository: bytecodealliance/wasmtime
Pull request #7741 (2024-01-03 07:23:22)

docs: fix typos
docs: fix typos


Patch:
diff --git a/build.rs b/build.rs
index 730ca8e83..5e8ef0a78 100644
--- a/build.rs
+++ b/build.rs
@@ -216,6 +216,9 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
             "table_copy",
             "table_set",
             "table_get",
+            "memory_grow",
+            "memory_init",
+            "memory_fill",
         ]
         .contains(&testname);
 
@@ -230,7 +233,7 @@ fn ignore(testsuite: &str, testname: &str, strategy: &str) -> bool {
             }
         }
         if testsuite == "spec_testsuite" {
-            // The official table init and table copy tests are now supported.
+            // The official following tests are supported.
             return !["table_init", "table_copy"].contains(&testname);
         }
 
diff --git a/ci/merge-artifacts.sh b/ci/merge-artifacts.sh
index aece95e6c..036911cab 100755
--- a/ci/merge-artifacts.sh
+++ b/ci/merge-artifacts.sh
@@ -9,7 +9,7 @@
 
 set -ex
 
-# Prepare the upload folder and move all aritfacts that aren't being merged into
+# Prepare the upload folder and move all artifacts that aren't being merged into
 # this folder, e.g. the MSI installer and adapter wasm files.
 rm -rf dist
 mkdir dist
diff --git a/docs/contributing-release-process.md b/docs/contributing-release-process.md
index b25d69056..1fa5483d9 100644
--- a/docs/contributing-release-process.md
+++ b/docs/contributing-release-process.md
@@ -6,7 +6,7 @@ others might be curious in this as well!
 
 ## Releasing a major version
 
-Major versions of Wasmtime are relased once-a-month. Most of this is automatic
+Major versions of Wasmtime are released once-a-month. Most of this is automatic
 and all that needs to be done is to merge GitHub PRs that CI will
 generate. At a high-level the structure of Wasmtime's release process is:
 
diff --git a/docs/examples-profiling-vtune.md b/docs/examples-profiling-vtune.md
index 61c67d1b5..9fb45b385 100644
--- a/docs/examples-profiling-vtune.md
+++ b/docs/examples-profiling-vtune.md
@@ -4,7 +4,7 @@
 and 64-bit x86 architectures. The tool collects profiling data during runtime
 and then, either through the command line or GUI, provides a variety of options
 for viewing and analyzing that data. VTune Profiler is available in both
-commerical and free options. The free, downloadable version is available
+commercial and free options. The free, downloadable version is available
 [here][download] and is backed by a community forum for support. This version is
 appropriate for detailed analysis of your Wasm program.
 
@@ -65,7 +65,7 @@ This command tells the VTune collector (`vtune`) to collect hot spot
 profiling data as Wasmtime is executing `foo.wasm`. The `--profile=vtune` flag enables
 VTune support in Wasmtime so that the collector is also alerted to JIT events
 that take place during runtime. The first time this is run, the result of the
-command is a results diretory `r000hs/` which contains profiling data for
+command is a results directory `r000hs/` which contains profiling data for
 Wasmtime and the execution of `foo.wasm`. This data can then be read and
 displayed via the command line or via the VTune GUI by importing the result.
 
diff --git a/fuzz/fuzz_targets/differential.rs b/fuzz/fuzz_targets/differential.rs
index e166fa069..fa3f37dc1 100644
--- a/fuzz/fuzz_targets/differential.rs
+++ b/fuzz/fuzz_targets/differential.rs
@@ -436,7 +436,13 @@ fn winch_supports_module(module: &[u8]) -> bool {
                         | TableFill { .. }
                         | TableGrow { .. }
                         | TableSize { .. }
-                        | TableInit { .. } => {}
+                        | TableInit { .. }
+                        | MemoryCopy { .. }
+                        | MemoryGrow { .. }
+                        | MemoryFill { .. }
+                        | MemoryInit { .. }
+                        | DataDrop { .. }
+                        | MemorySize { .. } => {}
                         _ => {
                             supported = false;
                             break 'main;
diff --git a/winch/codegen/src/codegen/env.rs b/winch/codegen/src/codegen/env.rs
index 09293f228..48a690cf1 100644
--- a/winch/codegen/src/codegen/env.rs
+++ b/winch/codegen/src/codegen/env.rs
@@ -9,8 +9,8 @@ use std::collections::{
 };
 use wasmparser::BlockType;
 use wasmtime_environ::{
-    FuncIndex, GlobalIndex, ModuleTranslation, ModuleTypesBuilder, PtrSize, TableIndex, TablePlan,
-    TypeConvert, TypeIndex, VMOffsets, WasmFuncType, WasmHeapType, WasmType,
+    FuncIndex, GlobalIndex, MemoryIndex, ModuleTranslation, ModuleTypesBuilder, PtrSize,
+    TableIndex, TablePlan, TypeConvert, TypeIndex, VMOffsets, WasmFuncType, WasmHeapType, WasmType,
 };
 
 /// Table metadata.
@@ -20,15 +20,29 @@ pub struct TableData {
     pub offset: u32,
     /// The offset to the current elements field.
     pub current_elems_offset: u32,
-    /// If the table is imported, return the base
-    /// offset of the `from` field in `VMTableImport`.
-    pub base: Option<u32>,
+    /// If the table is imported, this field contains the offset to locate the
+    /// base of the table data.
+    pub import_from: Option<u32>,
     /// The size of the table elements.
     pub(crate) element_size: OperandSize,
     /// The size of the current elements field.
     pub(crate) current_elements_size: OperandSize,
 }
 
+/// Heap metadata.
+#[derive(Debug, Copy, Clone)]
+pub struct HeapData {
+    /// The offset to the base of the heap.
+    pub offset: u32,
+    /// The offset to the current length field.
+    pub current_length_offset: u32,
+    /// If the heap is imported, this field contains the offset to locate the
+    /// base of the heap.
+    pub import_from: Option<u32>,
+    /// The memory type (32 or 64).
+    pub ty: WasmType,
+}
+
 /// A function callee.
 /// It categorizes how the callee should be treated
 /// when performing the call.
@@ -95,6 +109,7 @@ pub struct FuncEnv<'a, 'translation: 'a, 'data: 'translation, P: PtrSize> {
     pub types: &'translation ModuleTypesBuilder,
     /// Track resolved table information.
     resolved_tables: HashMap<TableIndex, TableData>,
+    resolved_heaps: HashMap<MemoryIndex, HeapData>,
 }
 
 pub fn ptr_type_from_ptr_size(size: u8) -> WasmType {
@@ -115,6 +130,7 @@ impl<'a, 'translation, 'data, P: PtrSize> FuncEnv<'a, 'translation, 'data, P> {
             translation,
             types,
             resolved_tables: HashMap::new(),
+            resolved_heaps: HashMap::new(),
         }
     }
 
@@ -222,7 +238,7 @@ impl<'a, 'translation, 'data, P: PtrSize> FuncEnv<'a, 'translation, 'data, P> {
                     };
 
                 *entry.insert(TableData {
-                    base: from_offset,
+                    import_from: from_offset,
                     offset: base_offset,
                     current_elems_offset,
                     element_size: OperandSize::from_bytes(self.vmoffsets.ptr.size()),
@@ -234,6 +250,48 @@ impl<'a, 'translation, 'data, P: PtrSize> FuncEnv<'a, 'translation, 'data, P> {
         }
     }
 
+    /// Resolved a [HeapData] from a [MemoryIndex].
+    // TODO: (@saulecabrera)
+    // Handle shared memories when implementing support for Wasm Threads.
+    pub fn resolve_heap(&mut self, index: MemoryIndex) -> HeapData {
+        match self.resolved_heaps.entry(index) {
+            Occupied(entry) => *entry.get(),
+            Vacant(entry) => {
+                let (import_from, base_offset, current_length_offset) =
+                    match self.translation.module.defined_memory_index(index) {
+                        Some(defined) => {
+                            let owned = self.translation.module.owned_memory_index(defined);
+                            (
+                                None,
+                                self.vmoffsets.vmctx_vmmemory_definition_base(owned),
+                                self.vmoffsets
+                                    .vmctx_vmmemory_definition_current_length(owned),
+                            )
+                        }
+                        None => (
+                            Some(self.vmoffsets.vmctx_vmmemory_import_from(index)),
+                            self.vmoffsets.ptr.vmmemory_definition_base().into(),
+                            self.vmoffsets
+                                .ptr
+                                .vmmemory_definition_current_length()
+                                .into(),
+                        ),
+                    };
+
+                *entry.insert(HeapData {
+                    offset: base_offset,
+                    import_from,
+                    current_length_offset,
+                    ty: if self.translation.module.memory_plans[index].memory.memory64 {
+                        WasmType::I64
+                    } else {
+                        WasmType::I32
+                    },
+                })
+            }
+        }
+    }
+
     /// Get a [`TablePlan`] from a [`TableIndex`].
     pub fn table_plan(&mut self, index: TableIndex) -> &TablePlan {
         &self.translation.module.table_plans[index]
diff --git a/winch/codegen/src/isa/aarch64/masm.rs b/winch/codegen/src/isa/aarch64/masm.rs
index 74ce2d96e..714913489 100644
--- a/winch/codegen/src/isa/aarch64/masm.rs
+++ b/winch/codegen/src/isa/aarch64/masm.rs
@@ -1,7 +1,7 @@
 use super::{abi::Aarch64ABI, address::Address, asm::Assembler, regs};
 use crate::{
     abi::{self, local::LocalSlot},
-    codegen::{ptr_type_from_ptr_size, CodeGenContext, TableData},
+    codegen::{ptr_type_from_ptr_size, CodeGenContext, HeapData, TableData},
     isa::reg::Reg,
     masm::{
         CalleeKind, DivKind, ExtendKind, FloatCmpKind, Imm as I, IntCmpKind,
@@ -116,6 +116,10 @@ impl Masm for MacroAssembler {
         todo!()
     }
 
+    fn memory_size(&mut self, _heap_data: &HeapData, _context: &mut CodeGenContext) {
+        todo!()
+    }
+
     fn address_from_sp(&self, _offset: SPOffset) -> Self::Address {
         todo!()
     }
diff --git a/winch/codegen/src/isa/x64/masm.rs b/winch/codegen/src/isa/x64/masm.rs
index c5ea1ac88..e01eb6d34 100644
--- a/winch/codegen/src/isa/x64/masm.rs
+++ b/winch/codegen/src/isa/x64/masm.rs
@@ -27,7 +27,7 @@ use cranelift_codegen::{
     isa::x64::settings as x64_settings, settings, Final, MachBufferFinalized, MachLabel,
 };
 
-use wasmtime_environ::PtrSize;
+use wasmtime_environ::{PtrSize, WasmType, WASM_PAGE_SIZE};
 
 /// x64 MacroAssembler.
 pub(crate) struct MacroAssembler {
@@ -137,7 +137,7 @@ impl Masm for MacroAssembler {
         let bound = context.any_gpr(self);
         let tmp = context.any_gpr(self);
 
-        if let Some(offset) = table_data.base {
+        if let Some(offset) = table_data.import_from {
             // If the table data declares a particular offset base,
             // load the address into a register to further use it as
             // the table address.
@@ -192,7 +192,7 @@ impl Masm for MacroAssembler {
         let scratch = regs::scratch();
         let size = context.any_gpr(self);
 
-        if let Some(offset) = table_data.base {
+        if let Some(offset) = table_data.import_from {
             self.asm
                 .mov_mr(&self.address_at_vmctx(offset), scratch, self.ptr_size);
         } else {
@@ -206,6 +206,44 @@ impl Masm for MacroAssembler {
         context.stack.push(TypedReg::i32(size).into());
     }
 
+    fn memory_size(&mut self, heap_data: &crate::codegen::HeapData, context: &mut CodeGenContext) {
+        let size_reg = context.any_gpr(self);
+        let scratch = regs::scratch();
+        let vmctx = <Self::ABI as ABI>::vmctx_reg();
+
+        let base = if let Some(offset) = heap_data.import_from {
+            self.asm
+                .mov_mr(&self.address_at_vmctx(offset), scratch, self.ptr_size);
+            scratch
+        } else {
+            vmctx
+        };
+
+        let size_addr = Address::offset(base, heap_data.current_length_offset);
+        self.asm.mov_mr(&size_addr, size_reg, self.ptr_size);
+        // Prepare the stack to emit a shift to get the size in pages rather
+        // than in bytes.
+        context
+            .stack
+            .push(TypedReg::new(heap_data.ty, size_reg).into());
+
+        // Since the page size is a power-of-two, verify that 2^16, equals the
+        // defined constant. This is mostly a safeguard in case the constant
+        // value ever changes.
+        let pow = 16;
+        debug_assert_eq!(2u32.pow(pow), WASM_PAGE_SIZE);
+
+        // Ensure that the constant is correctly typed according to the heap
+        // type to reduce register pressure when emitting the shift operation.
+        match heap_data.ty {
+            WasmType::I32 => context.stack.push(Val::i32(pow as i32)),
+            WasmType::I64 => context.stack.push(Val::i64(pow as i64)),
+            _ => unreachable!(),
+        }
+
+        self.shift(context, ShiftKind::ShrU, heap_data.ty.into());
+    }
+
     fn address_from_sp(&self, offset: SPOffset) -> Self::Address {
         Address::offset(regs::rsp(), self.sp_offset - offset.as_u32())
     }
diff --git a/winch/codegen/src/masm.rs b/winch/codegen/src/masm.rs
index 42ea92f97..33d1cc940 100644
--- a/winch/codegen/src/masm.rs
+++ b/winch/codegen/src/masm.rs
@@ -1,5 +1,5 @@
 use crate::abi::{self, align_to, LocalSlot};
-use crate::codegen::{ptr_type_from_ptr_size, CodeGenContext, TableData};
+use crate::codegen::{ptr_type_from_ptr_size, CodeGenContext, HeapData, TableData};
 use crate::isa::reg::Reg;
 use cranelift_codegen::{ir::LibCall, Final, MachBufferFinalized, MachLabel};
 use std::{fmt::Debug, ops::Range};
@@ -375,6 +375,9 @@ pub(crate) trait MacroAssembler {
     /// Retrieves the size of the table, pushing the result to the value stack.
     fn table_size(&mut self, table_data: &TableData, context: &mut CodeGenContext);
 
+    /// Retrieves the size of the memory, pushing the result to the value stack.
+    fn memory_size(&mut self, heap_data: &HeapData, context: &mut CodeGenContext);
+
     /// Constructs an address with an offset that is relative to the
     /// current position of the stack pointer (e.g. [sp + (sp_offset -
     /// offset)].
diff --git a/winch/codegen/src/visitor.rs b/winch/codegen/src/visitor.rs
index a82ecce9a..4afc9a895 100644
--- a/winch/codegen/src/visitor.rs
+++ b/winch/codegen/src/visitor.rs
@@ -16,7 +16,7 @@ use smallvec::SmallVec;
 use wasmparser::BrTable;
 use wasmparser::{BlockType, Ieee32, Ieee64, VisitOperator};
 use wasmtime_environ::{
-    FuncIndex, GlobalIndex, TableIndex, TableStyle, TypeIndex, WasmHeapType, WasmType,
+    FuncIndex, GlobalIndex, MemoryIndex, TableIndex, TableStyle, TypeIndex, WasmHeapType, WasmType,
     FUNCREF_INIT_BIT,
 };
 
@@ -179,6 +179,12 @@ macro_rules! def_unsupported {
     (emit TableSize $($rest:tt)*) => {};
     (emit TableFill $($rest:tt)*) => {};
     (emit ElemDrop $($rest:tt)*) => {};
+    (emit MemoryInit $($rest:tt)*) => {};
+    (emit MemoryCopy $($rest:tt)*) => {};
+    (emit DataDrop $($rest:tt)*) => {};
+    (emit MemoryFill $($rest:tt)*) => {};
+    (emit MemorySize $($rest:tt)*) => {};
+    (emit MemoryGrow $($rest:tt)*) => {};
 
     (emit $unsupported:tt $($rest:tt)*) => {$($rest)*};
 }
@@ -1239,6 +1245,97 @@ where
         });
     }
 
+    fn visit_memory_init(&mut self, data_index: u32, mem: u32) {
+        debug_assert!(self.context.stack.len() >= 3);
+        let ptr_type = self.env.ptr_type();
+        let at = self.context.stack.len() - 3;
+        let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
+        self.context.stack.insert_many(
+            at,
+            [
+                vmctx.into(),
+                mem.try_into().unwrap(),
+                data_index.try_into().unwrap(),
+            ],
+        );
+        FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |cx| {
+            Callee::Builtin(cx.builtins.memory_init::<M::ABI, M::Ptr>())
+        });
+    }
+
+    fn visit_memory_copy(&mut self, dst_mem: u32, src_mem: u32) {
+        // At this point, the stack is expected to contain:
+        //     [ dst_offset, src_offset, len ]
+        // The following code inserts the missing params, so that stack contains:
+        //     [ vmctx, dst_mem, dst_offset, src_mem, src_offset, len ]
+        // Which is the order expected by the builtin function.
+        debug_assert!(self.context.stack.len() >= 3);
+        let ptr_type = self.env.ptr_type();
+        let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
+        let at = self.context.stack.len() - 2;
+        self.context
+            .stack
+            .insert_many(at, [src_mem.try_into().unwrap()]);
+
+        // One element was inserted above, so instead of 3, we use 4.
+        let at = self.context.stack.len() - 4;
+        self.context
+            .stack
+            .insert_many(at, [vmctx.into(), dst_mem.try_into().unwrap()]);
+
+        FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |cx| {
+            Callee::Builtin(cx.builtins.memory_copy::<M::ABI, M::Ptr>())
+        });
+    }
+
+    fn visit_memory_fill(&mut self, mem: u32) {
+        debug_assert!(self.context.stack.len() >= 3);
+        let ptr_type = self.env.ptr_type();
+        let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
+        let at = self.context.stack.len() - 3;
+
+        self.context
+            .stack
+            .insert_many(at, [vmctx.into(), mem.try_into().unwrap()]);
+
+        FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |cx| {
+            Callee::Builtin(cx.builtins.memory_fill::<M::ABI, M::Ptr>())
+        });
+    }
+
+    fn visit_memory_size(&mut self, mem: u32, _: u8) {
+        let heap = self.env.resolve_heap(MemoryIndex::from_u32(mem));
+        self.masm.memory_size(&heap, &mut self.context);
+    }
+
+    fn visit_memory_grow(&mut self, mem: u32, _: u8) {
+        debug_assert!(self.context.stack.len() >= 1);
+        let ptr_type = self.env.ptr_type();
+        let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
+        let at = self.context.stack.len() - 1;
+        // The stack at this point contains: [ delta ]
+        // The desired state is
+        //   [ vmctx, delta, index ]
+        self.context.stack.insert_many(at, [vmctx.into()]);
+        self.context.stack.extend([mem.try_into().unwrap()]);
+
+        FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |cx| {
+            Callee::Builtin(cx.builtins.memory32_grow::<M::ABI, M::Ptr>())
+        });
+    }
+
+    fn visit_data_drop(&mut self, data_index: u32) {
+        let ptr_type = self.env.ptr_type();
+        let vmctx = TypedReg::new(ptr_type, <M::ABI as ABI>::vmctx_reg());
+        self.context
+            .stack
+            .extend([vmctx.into(), data_index.try_into().unwrap()]);
+
+        FnCall::emit::<M, M::Ptr, _>(self.masm, &mut self.context, |cx| {
+            Callee::Builtin(cx.builtins.data_drop::<M::ABI, M::Ptr>())
+        });
+    }
+
     fn visit_nop(&mut self) {}
 
     fn visit_if(&mut self, blockty: BlockType) {


Test patch:
diff --git a/tests/misc_testsuite/winch/memory_fill.wast b/tests/misc_testsuite/winch/memory_fill.wast
new file mode 100644
index 000000000..b37896de3
--- /dev/null
+++ b/tests/misc_testsuite/winch/memory_fill.wast
@@ -0,0 +1,57 @@
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+    (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 256))))
+(invoke "test")
+
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+    (memory.fill (i32.const 0xFF00) (i32.const 0x55) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+    (memory.fill (i32.const 0xFFFFFF00) (i32.const 0x55) (i32.const 257))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+    (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 0))))
+(invoke "test")
+
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+    (memory.fill (i32.const 0x10000) (i32.const 0x55) (i32.const 0))))
+(invoke "test")
+
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+    (memory.fill (i32.const 0x20000) (i32.const 0x55) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+    (memory.fill (i32.const 0x1) (i32.const 0xAA) (i32.const 0xFFFE))))
+(invoke "test")
+
+
+(module
+  (memory 1 1)
+  
+  (func (export "test")
+     (memory.fill (i32.const 0x12) (i32.const 0x55) (i32.const 10))
+     (memory.fill (i32.const 0x15) (i32.const 0xAA) (i32.const 4))))
+(invoke "test")
diff --git a/tests/misc_testsuite/winch/memory_grow.wast b/tests/misc_testsuite/winch/memory_grow.wast
new file mode 100644
index 000000000..7d763d62f
--- /dev/null
+++ b/tests/misc_testsuite/winch/memory_grow.wast
@@ -0,0 +1,211 @@
+(module
+  (memory 0)
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 800)) (i32.const 3))
+(assert_return (invoke "grow" (i32.const 0x10000)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 64736)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 803))
+
+(module
+  (memory 0 10)
+  (func (export "grow") (param i32) (result i32) (memory.grow (local.get 0)))
+)
+
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const 1))
+(assert_return (invoke "grow" (i32.const 2)) (i32.const 2))
+(assert_return (invoke "grow" (i32.const 6)) (i32.const 4))
+(assert_return (invoke "grow" (i32.const 0)) (i32.const 10))
+(assert_return (invoke "grow" (i32.const 1)) (i32.const -1))
+(assert_return (invoke "grow" (i32.const 0x10000)) (i32.const -1))
+
+;; As the argument of control constructs and instructions
+
+(module
+  (memory 1)
+
+  (func (export "as-br-value") (result i32)
+    (block (result i32) (br 0 (memory.grow (i32.const 0))))
+  )
+
+  (func (export "as-br_if-cond")
+    (block (br_if 0 (memory.grow (i32.const 0))))
+  )
+  (func (export "as-br_if-value") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (memory.grow (i32.const 0)) (i32.const 1))) (i32.const 7)
+    )
+  )
+  (func (export "as-br_if-value-cond") (result i32)
+    (block (result i32)
+      (drop (br_if 0 (i32.const 6) (memory.grow (i32.const 0)))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-br_table-index")
+    (block (br_table 0 0 0 (memory.grow (i32.const 0))))
+  )
+  (func (export "as-br_table-value") (result i32)
+    (block (result i32)
+      (br_table 0 0 0 (memory.grow (i32.const 0)) (i32.const 1)) (i32.const 7)
+    )
+  )
+  (func (export "as-br_table-value-index") (result i32)
+    (block (result i32)
+      (br_table 0 0 (i32.const 6) (memory.grow (i32.const 0))) (i32.const 7)
+    )
+  )
+
+  (func (export "as-return-value") (result i32)
+    (return (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-if-cond") (result i32)
+    (if (result i32) (memory.grow (i32.const 0))
+      (then (i32.const 0)) (else (i32.const 1))
+    )
+  )
+  (func (export "as-if-then") (result i32)
+    (if (result i32) (i32.const 1)
+      (then (memory.grow (i32.const 0))) (else (i32.const 0))
+    )
+  )
+  (func (export "as-if-else") (result i32)
+    (if (result i32) (i32.const 0)
+      (then (i32.const 0)) (else (memory.grow (i32.const 0)))
+    )
+  )
+
+  (func (export "as-select-first") (param i32 i32) (result i32)
+    (select (memory.grow (i32.const 0)) (local.get 0) (local.get 1))
+  )
+  (func (export "as-select-second") (param i32 i32) (result i32)
+    (select (local.get 0) (memory.grow (i32.const 0)) (local.get 1))
+  )
+  (func (export "as-select-cond") (result i32)
+    (select (i32.const 0) (i32.const 1) (memory.grow (i32.const 0)))
+  )
+
+  (func $f (param i32 i32 i32) (result i32) (i32.const -1))
+  (func (export "as-call-first") (result i32)
+    (call $f (memory.grow (i32.const 0)) (i32.const 2) (i32.const 3))
+  )
+  (func (export "as-call-mid") (result i32)
+    (call $f (i32.const 1) (memory.grow (i32.const 0)) (i32.const 3))
+  )
+  (func (export "as-call-last") (result i32)
+    (call $f (i32.const 1) (i32.const 2) (memory.grow (i32.const 0)))
+  )
+
+  (type $sig (func (param i32 i32 i32) (result i32)))
+  (table funcref (elem $f))
+  (func (export "as-call_indirect-first") (result i32)
+    (call_indirect (type $sig)
+      (memory.grow (i32.const 0)) (i32.const 2) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-mid") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (memory.grow (i32.const 0)) (i32.const 3) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-last") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (memory.grow (i32.const 0)) (i32.const 0)
+    )
+  )
+  (func (export "as-call_indirect-index") (result i32)
+    (call_indirect (type $sig)
+      (i32.const 1) (i32.const 2) (i32.const 3) (memory.grow (i32.const 0))
+    )
+  )
+
+  (func (export "as-local.set-value") (local i32)
+    (local.set 0 (memory.grow (i32.const 0)))
+  )
+  (func (export "as-local.tee-value") (result i32) (local i32)
+    (local.tee 0 (memory.grow (i32.const 0)))
+  )
+  (global $g (mut i32) (i32.const 0))
+  (func (export "as-global.set-value") (local i32)
+    (global.set $g (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-unary-operand") (result i32)
+    (i32.clz (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-binary-left") (result i32)
+    (i32.add (memory.grow (i32.const 0)) (i32.const 10))
+  )
+  (func (export "as-binary-right") (result i32)
+    (i32.sub (i32.const 10) (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-test-operand") (result i32)
+    (i32.eqz (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-compare-left") (result i32)
+    (i32.le_s (memory.grow (i32.const 0)) (i32.const 10))
+  )
+  (func (export "as-compare-right") (result i32)
+    (i32.ne (i32.const 10) (memory.grow (i32.const 0)))
+  )
+
+  (func (export "as-memory.grow-size") (result i32)
+    (memory.grow (memory.grow (i32.const 0)))
+  )
+)
+
+(assert_return (invoke "as-br-value") (i32.const 1))
+
+(assert_return (invoke "as-br_if-cond"))
+(assert_return (invoke "as-br_if-value") (i32.const 1))
+(assert_return (invoke "as-br_if-value-cond") (i32.const 6))
+
+(assert_return (invoke "as-br_table-index"))
+(assert_return (invoke "as-br_table-value") (i32.const 1))
+(assert_return (invoke "as-br_table-value-index") (i32.const 6))
+
+(assert_return (invoke "as-return-value") (i32.const 1))
+
+(assert_return (invoke "as-if-cond") (i32.const 0))
+(assert_return (invoke "as-if-then") (i32.const 1))
+(assert_return (invoke "as-if-else") (i32.const 1))
+
+(assert_return (invoke "as-select-first" (i32.const 0) (i32.const 1)) (i32.const 1))
+(assert_return (invoke "as-select-second" (i32.const 0) (i32.const 0)) (i32.const 1))
+(assert_return (invoke "as-select-cond") (i32.const 0))
+
+(assert_return (invoke "as-call-first") (i32.const -1))
+(assert_return (invoke "as-call-mid") (i32.const -1))
+(assert_return (invoke "as-call-last") (i32.const -1))
+
+(assert_return (invoke "as-call_indirect-first") (i32.const -1))
+(assert_return (invoke "as-call_indirect-mid") (i32.const -1))
+(assert_return (invoke "as-call_indirect-last") (i32.const -1))
+(assert_trap (invoke "as-call_indirect-index") "undefined element")
+
+(assert_return (invoke "as-local.set-value"))
+(assert_return (invoke "as-local.tee-value") (i32.const 1))
+(assert_return (invoke "as-global.set-value"))
+
+(assert_return (invoke "as-unary-operand") (i32.const 31))
+
+(assert_return (invoke "as-binary-left") (i32.const 11))
+(assert_return (invoke "as-binary-right") (i32.const 9))
+
+(assert_return (invoke "as-test-operand") (i32.const 0))
+
+(assert_return (invoke "as-compare-left") (i32.const 1))
+(assert_return (invoke "as-compare-right") (i32.const 1))
+
+(assert_return (invoke "as-memory.grow-size") (i32.const 1))
diff --git a/tests/misc_testsuite/winch/memory_init.wast b/tests/misc_testsuite/winch/memory_init.wast
new file mode 100644
index 000000000..238412350
--- /dev/null
+++ b/tests/misc_testsuite/winch/memory_init.wast
@@ -0,0 +1,742 @@
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data "\05\09\02\07\06")
+  (func (export "test")
+    (nop))
+)
+
+(invoke "test")
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data "\05\09\02\07\06")
+  (func (export "test")
+    (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4)))
+)
+
+(invoke "test")
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data "\05\09\02\07\06")
+  (func (export "test")
+    (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3)))
+)
+
+(invoke "test")
+
+(module
+  (memory (export "memory0") 1 1)
+  (data (i32.const 2) "\03\01\04\01")
+  (data "\02\07\01\08")
+  (data (i32.const 12) "\07\05\02\03\06")
+  (data "\05\09\02\07\06")
+  (func (export "test")
+    (memory.init 1 (i32.const 7) (i32.const 0) (i32.const 4))
+    (data.drop 1)
+    (memory.init 3 (i32.const 15) (i32.const 1) (i32.const 3))
+    (data.drop 3)
+    (memory.copy (i32.const 20) (i32.const 15) (i32.const 5))
+    (memory.copy (i32.const 21) (i32.const 29) (i32.const 1))
+    (memory.copy (i32.const 24) (i32.const 10) (i32.const 1))
+    (memory.copy (i32.const 13) (i32.const 11) (i32.const 4))
+    (memory.copy (i32.const 19) (i32.const 20) (i32.const 5)))
+)
+
+(invoke "test")
+
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (data.drop 0)
+    (data.drop 0)))
+(invoke "test")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (data.drop 0)
+    (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+   (memory 1)
+   (data (i32.const 0) "\37")
+   (func (export "test")
+     (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 1))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(assert_invalid
+  (module
+    (func (export "test")
+      (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))))
+  "unknown memory 0")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 1 (i32.const 1234) (i32.const 1) (i32.const 1))))
+  "unknown data segment 1")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))
+    (memory.init 0 (i32.const 1) (i32.const 0) (i32.const 1))))
+(invoke "test")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 0) (i32.const 5))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 2) (i32.const 3))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 4) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 1234) (i32.const 1) (i32.const 0))))
+(invoke "test")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 0x10001) (i32.const 0) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 0x10000) (i32.const 0) (i32.const 0))))
+(invoke "test")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 0x10000) (i32.const 1) (i32.const 0))))
+(invoke "test")
+
+(module
+  (memory 1)
+    (data "\37")
+  (func (export "test")
+    (memory.init 0 (i32.const 0x10001) (i32.const 4) (i32.const 0))))
+(assert_trap (invoke "test") "out of bounds memory access")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f32.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (i64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f32.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (i64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (i32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (f32.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (i64.const 1))))
+  "type mismatch")
+
+(assert_invalid
+  (module
+    (memory 1)
+    (data "\37")
+    (func (export "test")
+      (memory.init 0 (f64.const 1) (f64.const 1) (f64.const 1))))
+  "type mismatch")
+
+(module
+  (memory 1 1 )
+  (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65528) (i32.const 16))
+              "out of bounds memory access")
+
+(module
+  (memory 1 1 )
+  (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65527) (i32.const 16))
+              "out of bounds memory access")
+(module
+  (memory 1 1 )
+  (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65472) (i32.const 30))
+              "out of bounds memory access")
+
+(module
+  (memory 1 1 )
+  (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65473) (i32.const 31))
+              "out of bounds memory access")
+(module
+  (memory 1  )
+  (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 65528) (i32.const 4294967040))
+              "out of bounds memory access")
+
+(module
+  (memory 1  )
+  (data "\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42\42")
+   
+  (func (export "run") (param $offs i32) (param $len i32)
+    (memory.init 0 (local.get $offs) (i32.const 0) (local.get $len))))
+
+(assert_trap (invoke "run" (i32.const 0) (i32.const 4294967292))
+              "out of bounds memory access")
+
+(module
+  (memory 1)
+  ;; 65 data segments. 64 is the smallest positive number that is encoded
+  ;; differently as a signed LEB.
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "") (data "") (data "") (data "") (data "") (data "") (data "") (data "")
+  (data "")
+  (func (memory.init 64 (i32.const 0) (i32.const 0) (i32.const 0))))
diff --git a/tests/misc_testsuite/winch/memory_size.wast b/tests/misc_testsuite/winch/memory_size.wast
new file mode 100644
index 000000000..239e66d8f
--- /dev/null
+++ b/tests/misc_testsuite/winch/memory_size.wast
@@ -0,0 +1,85 @@
+(module
+  (memory 0)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 4)))
+(assert_return (invoke "size") (i32.const 5))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 5))
+
+(module
+  (memory 1)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 2))
+(assert_return (invoke "grow" (i32.const 4)))
+(assert_return (invoke "size") (i32.const 6))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 6))
+
+(module
+  (memory 0 2)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 3)))
+(assert_return (invoke "size") (i32.const 0))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 4)))
+(assert_return (invoke "size") (i32.const 1))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 2))
+
+(module
+  (memory 3 8)
+  (func (export "size") (result i32) (memory.size))
+  (func (export "grow") (param $sz i32) (drop (memory.grow (local.get $sz))))
+)
+
+(assert_return (invoke "size") (i32.const 3))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 4))
+(assert_return (invoke "grow" (i32.const 3)))
+(assert_return (invoke "size") (i32.const 7))
+(assert_return (invoke "grow" (i32.const 0)))
+(assert_return (invoke "size") (i32.const 7))
+(assert_return (invoke "grow" (i32.const 2)))
+(assert_return (invoke "size") (i32.const 7))
+(assert_return (invoke "grow" (i32.const 1)))
+(assert_return (invoke "size") (i32.const 8))
+
+
+;; Type errors
+
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-result-i32-vs-empty
+      (memory.size)
+    )
+  )
+  "type mismatch"
+)
+(assert_invalid
+  (module
+    (memory 1)
+    (func $type-result-i32-vs-f32 (result f32)
+      (memory.size)
+    )
+  )
+  "type mismatch"
+)