Skip to content

Commit

Permalink
doc(examples): Clean and comment the memory example
Browse files Browse the repository at this point in the history
Closes #1749
  • Loading branch information
jubianchi committed Nov 3, 2020
1 parent 592931d commit fe68760
Showing 1 changed file with 91 additions and 24 deletions.
115 changes: 91 additions & 24 deletions examples/memory.rs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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<i32, i32> = 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(())
}

0 comments on commit fe68760

Please sign in to comment.