From 5544fb104575138e9f835471e63ed748d19bd456 Mon Sep 17 00:00:00 2001 From: jubianchi Date: Fri, 30 Oct 2020 16:02:51 +0100 Subject: [PATCH] doc(examples): Clean and comment the memory example Closes #1749 --- examples/memory.rs | 115 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 91 insertions(+), 24 deletions(-) diff --git a/examples/memory.rs b/examples/memory.rs index 9da6d8131b2..123b55542b2 100644 --- a/examples/memory.rs +++ b/examples/memory.rs @@ -1,11 +1,32 @@ -use wasmer::{imports, wat2wasm, Instance, Module, NativeFunc, Pages, Store}; +//! With Wasmer you'll be able to interact with guest module memory. +//! +//! This example illustrates the basics of the basics of interacting with Wasm module memory.: +//! +//! 1. How to load a Wasm modules as bytes +//! 2. How to compile the module +//! 3. How to create an instance of the module +//! +//! You can run the example directly by executing in Wasmer root: +//! +//! ```shell +//! cargo run --example memory --release --features "cranelift" +//! ``` +//! +//! Ready? + +use wasmer::{imports, wat2wasm, Instance, Module, NativeFunc, Pages, Store, Bytes}; use wasmer_compiler_cranelift::Cranelift; use wasmer_engine_jit::JIT; +use std::mem; // this example is a work in progress: // TODO: clean it up and comment it https://github.com/wasmerio/wasmer/issues/1749 fn main() -> anyhow::Result<()> { + // Let's declare the Wasm module. + // + // We are using the text representation of the module here but you can also load `.wasm` + // files using the `include_bytes!` macro. let wasm_bytes = wat2wasm( r#" (module @@ -32,48 +53,94 @@ fn main() -> anyhow::Result<()> { .as_bytes(), )?; - // We set up our store with an engine and a compiler. + // Create a Store. + // Note that we don't need to specify the engine/compiler if we want to use + // the default provided by Wasmer. + // You can use `Store::default()` for that. let store = Store::new(&JIT::new(&Cranelift::default()).engine()); - // Then compile our Wasm. + + println!("Compiling module..."); + // Let's compile the Wasm module. let module = Module::new(&store, wasm_bytes)?; + + // Create an empty import object. let import_object = imports! {}; - // And instantiate it with no imports. + + println!("Instantiating module..."); + // Let's instantiate the Wasm module. let instance = Instance::new(&module, &import_object)?; + // The module exports some utility functions, let's get them. + // + // These function will be used later in this example. let mem_size: NativeFunc<(), i32> = instance.exports.get_native_function("mem_size")?; let get_at: NativeFunc = instance.exports.get_native_function("get_at")?; let set_at: NativeFunc<(i32, i32), ()> = instance.exports.get_native_function("set_at")?; let memory = instance.exports.get_memory("memory")?; - let mem_addr = 0x2220; - let val = 0xFEFEFFE; - + // We now have an instance ready to be used. + // + // We will start by querying the most intersting information + // about the memory: its size. There are mainly two ways of getting + // this: + // * the size as a number of `Page`s + // * the size as a number of bytes + // + // The size in bytes can be found either by querying its pages or by + // querying the memory directly. + println!("Querying memory size..."); assert_eq!(memory.size(), Pages::from(1)); + assert_eq!(memory.size().bytes(), Bytes::from(65536 as usize)); + assert_eq!(memory.data_size(), 65536); + + // Sometimes, the guest module may also export a function to let you + // query the memory. Here we have a `mem_size` function, let's try it: + let result = mem_size.call()?; + println!("Memory size: {:?}", result); + assert_eq!(Pages::from(result as u32), memory.size()); + + + // Now that we know the size of our memory, it's time to see how wa + // can change this. + // + // A memory can be grown to allow storing more things into it. Let's + // see how we can do that: + println!("Growing memory..."); + // Here we are requesting two more pages for our memory. memory.grow(2)?; assert_eq!(memory.size(), Pages::from(3)); - let result = mem_size.call()?; - assert_eq!(result, 3); - // ------------- + // From an `Instance` we can fetch any exported entities from the Wasm module. + // Each of these entities is covered in others examples. + // + // Here we are fetching the exported function. We won't go into details here + // as the main focus of this example is to show how to create an instance out + // of a Wasm module and have basic interactions with it. + + // Now that we know how to query and adjust the size of the memory, + // let's see how wa can write to it or read from it. + // + // We'll only focus on how to do this using exported function, the goal + // is to show how to work with memory addresses. Here we'll use absolute + // addresses to write and read a value. + let mem_addr = 0x2220; + let val = 0xFEFEFFE; set_at.call(mem_addr, val)?; - // ------------- + let result = get_at.call(mem_addr)?; + println!("Value at {:#x?}: {:?}", mem_addr, result); + assert_eq!(result, val); + + // Now instead of using hard coded memory addresses, let's try to write + // something at the end of the second memory page and read it. let page_size = 0x1_0000; - let result = get_at.call(page_size * 3 - 4)?; - memory.grow(1025)?; - assert_eq!(result, 123456); - assert_eq!(memory.size(), Pages::from(1028)); - set_at.call(page_size * 1027 - 4, 123456)?; - let result = get_at.call(page_size * 1027 - 4)?; - assert_eq!(result, 123456); - set_at.call(1024, 123456)?; - let result = get_at.call(1024)?; - assert_eq!(result, 123456); - - // ------------- + let mem_addr = (page_size * 2) - mem::size_of_val(&val) as i32; + let val = 0xFEA09; + set_at.call(mem_addr, val)?; + let result = get_at.call(mem_addr)?; + println!("Value at {:#x?}: {:?}", mem_addr, result); assert_eq!(result, val); - // ------------- Ok(()) }