Project: WasmEdge Runtime (Runtime / Container Runtime)
File: memory_manipulation.md

In this example, we'll present how to manipulate the linear memory with the APIs defined in . The code in the following example is verified on wasmedge-sdk v0.5.0 wasmedge-sys v0.10.0 wasmedge-types v0.3.0 Before talking about the code, let's first see the wasm module we use in this example. In the wasm module, a linear memory of 1-page (64KiB) size is defined; in addition, three functions are exported from this module: `getat`, `setat`, and `mem_size`. ```wasm (module (type $memsizet (func (result i32))) (type $getatt (func (param i32) (result i32))) (type $setatt (func (param i32) (param i32))) (memory $mem 1) (func $getat (type $getat_t) (param $idx i32) (result i32) (i32.load (local.get $idx))) (func $setat (type $setat_t) (param $idx i32) (param $val i32) (i32.store (local.get $idx) (local.get $val))) (func $memsize (type $memsize_t) (result i32) (memory.size)) (export "getat" (func $getat)) (export "setat" (func $setat)) (export "memsize" (func $memsize)) (export "memory" (memory $mem))) ``` Next, we'll demonstrate how to manipulate the linear memory by calling the exported functions. Let's start off by getting all imports right away so you can follow along ```rust // please add this feature if you're using rust of version < 1.63 // #![feature(explicitgenericargswithimpl_trait)] use wasmedge_sdk::{params, wat2wasm, Executor, Module, Store, WasmVal}; ``` To load a `Module`, `wasmedge-sdk` defines two methods: loads a wasm module from a file, and meanwhile, validates the loaded wasm module. loads a wasm module from an array of in-memory bytes, and meanwhile, validates the loaded wasm module. Here we use `Module::from_bytes` method to load our wasm module from an array of in-memory bytes. ```rust let wasm_bytes = wat2wasm( r#" (module (type $memsizet (func (result i32))) (type $getatt (func (param i32) (result i32))) (type $setatt (func (param i32) (param i32))) (memory $mem 1) (func $getat (type $getat_t) (param $idx i32) (result i32) (i32.load (local.get $idx))) (func $setat (type $setat_t) (param $idx i32) (param $val i32) (i32.store (local.get $idx) (local.get $val))) (func $memsize (type $memsize_t) (result i32) (memory.size)) (export "getat" (func $getat)) (export "setat" (func $setat)) (export "memsize" (func $memsize)) (export "memory" (memory $mem))) "#

)?; // loads a wasm module from the given in-memory bytes let module = Module::frombytes(None, &wasmbytes)?; ``` The module returned by `Module::from_bytes` is a compiled module, also called AST Module in WasmEdge terminology. To use it in WasmEdge runtime environment, we need to instantiate the AST module. We use API to achieve the goal. ```rust // create an executor let mut executor = Executor::new(None, None)?; // create a store let mut store = Store::new()?; // register the module into the store let externinstance = store.registernamed_module(&mut executor, "extern", &module)?; ``` In the code above, we register the AST module into a `Store`, in which the module is instantiated, and as a result, a named `extern` is returned. In the previous section, we get an instance by registering a compiled module into the runtime environment. Now we retrieve the memory instance from the module instance, and make use of the APIs defined in to manipulate the linear memory. ```rust // get the exported memory instance let mut memory = extern_instance .memory("memory") .okorelse(|| anyhow::anyhow!("failed to get memory instance named 'memory'"))?; // check memory size assert_eq!(memory.size(), 1); asserteq!(memory.datasize(), 65536); // grow memory size memory.grow(2)?; assert_eq!(memory.size(), 3); asserteq!(memory.datasize(), 3 * 65536); // get the exported functions: "setat" and "getat" let setat = externinstance .func("set_at") .okorelse(|| anyhow::Error::msg("Not found exported function named 'set_at'."))?; let getat = externinstance .func("get_at") .okorelse(|| anyhow::Error::msg("Not found exported function named 'get_at`."))?; // call the exported function named "set_at" let mem_addr = 0x2220; let val = 0xFEFEFFE; setat.call(&mut executor, params!(memaddr, val))?; // call the exported function named "get_at" let returns = getat.call(&mut executor, params!(memaddr))?; asserteq!(returns[0].toi32(), val); // call the exported function named "set_at" let pagesize = 0x10000; let memaddr = (pagesize * 2) - std::mem::sizeofval(&val) as i32; let val = 0xFEA09; setat.call(&mut executor, params!(memaddr, val))?; // call the exported function named "get_at" let returns = getat.call(&mut executor, params!(memaddr))?; asserteq!(returns[0].toi32(), val); ``` The comments in the code explain the meaning of the code sample above, so we don't describe more. The complete code of this example can be found in .