Skip to content

Commit

Permalink
doc(examples): Add Memory examples
Browse files Browse the repository at this point in the history
  • Loading branch information
jubianchi committed Oct 26, 2020
1 parent 64bbfe6 commit 8245f36
Show file tree
Hide file tree
Showing 4 changed files with 220 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@ name = "exported-global"
path = "examples/exports_global.rs"
required-features = ["cranelift"]

[[example]]
name = "exported-memory"
path = "examples/exports_memory.rs"
required-features = ["cranelift"]

[[example]]
name = "imported-function"
path = "examples/imports_function.rs"
Expand Down
15 changes: 15 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,20 @@ example.

</details>

10. [**Exported memory**][exported-memory], explains how to read from
and write to exported memory.

_Keywords_: export, memory.

<details>
<summary><em>Execute the example</em></summary>

```shell
$ cargo run --example exported-memory --release --features "cranelift"
```

</details>

### Imports

10. [**Imported global**][imported-global], explains how to work with
Expand Down Expand Up @@ -237,6 +251,7 @@ example.
[cross-compilation]: ./engine_cross_compilation.rs
[exported-global]: ./exports_global.rs
[exported-function]: ./exports_function.rs
[exported-memory]: ./exports_memory.rs
[imported-global]: ./imports_global.rs
[imported-function]: ./imports_function.rs
[wasi]: ./wasi.rs
Expand Down
120 changes: 120 additions & 0 deletions examples/exports_memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//! A Wasm module can export entities, like functions, memories,
//! globals and tables.
//!
//! This example illustrates how to use exported memories
//!
//! You can run the example directly by executing in Wasmer root:
//!
//! ```shell
//! cargo run --example exported-memory --release --features "cranelift"
//! ```
//!
//! Ready?
use wasmer::{imports, wat2wasm, Array, Instance, Module, Store, WasmPtr};
use wasmer_compiler_cranelift::Cranelift;
use wasmer_engine_jit::JIT;

fn main() -> Result<(), Box<dyn std::error::Error>> {
// Let's declare the Wasm module with the text representation.
let wasm_bytes = wat2wasm(
br#"
(module
(memory (export "mem") 1)
(global $offset i32 (i32.const 42))
(global $length (mut i32) (i32.const 13))
(func (export "load") (result i32 i32)
global.get $offset
global.get $length)
(data (global.get $offset) "Hello, World!"))
"#,
)?;

// 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());

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! {};

println!("Instantiating module...");
// Let's instantiate the Wasm module.
let instance = Instance::new(&module, &import_object)?;

let load = instance
.exports
.get_native_function::<(), (WasmPtr<u8, Array>, i32)>("load")?;

// Here we go.
//
// The Wasm module exports a memory under "mem". Let's get it.
let memory = instance.exports.get_memory("mem")?;

// Now that we have the exported memory, let's get some
// information about it.
//
// The first thing we might be intersted in is the size of the memory.
// Let's get it!
println!("Memory size (pages) {:?}", memory.size());
println!("Memory size (bytes) {:?}", memory.data_size());

// Next, we'll want to read the contents of the memory.
//
// To do so, we have to get a `View` of the memory.
//let view = memory.view::<u8>();

// Oh! Wait, before reading the contents, we need to know
// where to find what we are looking for.
//
// Fortunately, the Wasm module exports a `load` function
// which will tell us the offset and length of the string.
let (ptr, length) = load.call()?;
println!("String offset: {:?}", ptr.offset());
println!("String length: {:?}", length);

// We now know where to fin our string, let's read it.
//
// We will get bytes out of the memory so we need to
// decode them into a string.
let str = ptr.get_utf8_string(memory, length as u32).unwrap();
println!("Memory contents: {:?}", str);

// What about changing the contents of the memory with a more
// appropriate string?
//
// To do that, we'll dereference our pointer and change the content
// of each `Cell`
let new_str = b"Hello, Wasmer!";
let values = ptr.deref(memory, 0, new_str.len() as u32).unwrap();
for i in 0..new_str.len() {
values[i].set(new_str[i]);
}

// And now, let's see the result.
//
// Since the new strings is bigger than the older one, we
// query the length again. The offset remains the same as
// before.
println!("New string length: {:?}", new_str.len());

let str = ptr.get_utf8_string(memory, new_str.len() as u32).unwrap();
println!("New memory contents: {:?}", str);

// Much better, don't you think?

Ok(())
}

#[test]
fn test_exported_memory() -> Result<(), Box<dyn std::error::Error>> {
main()
}
82 changes: 80 additions & 2 deletions lib/api/src/externals/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ impl Memory {
/// This function will construct the `Memory` using the store [`Tunables`].
///
/// [`Tunables`]: crate::tunables::Tunables
///
/// # Example
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
/// ```
pub fn new(store: &Store, ty: MemoryType) -> Result<Self, MemoryError> {
let tunables = store.tunables();
let style = tunables.memory_style(&ty);
Expand All @@ -46,11 +55,34 @@ impl Memory {
}

/// Returns the [`MemoryType`] of the `Memory`.
///
/// # Example
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let mt = MemoryType::new(1, None, false);
/// let m = Memory::new(&store, mt).unwrap();
///
/// assert_eq!(m.ty(), &mt);
/// ```
pub fn ty(&self) -> &MemoryType {
self.memory.ty()
}

/// Returns the [`Store`] where the `Memory` belongs.
///
/// # Example
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
///
/// assert_eq!(m.store(), &store);
/// ```
pub fn store(&self) -> &Store {
&self.store
}
Expand Down Expand Up @@ -92,16 +124,51 @@ impl Memory {
}

/// Returns the size (in [`Pages`]) of the `Memory`.
///
/// # Example
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
///
/// assert_eq!(m.size(), Pages(1));
/// ```
pub fn size(&self) -> Pages {
self.memory.size()
}

/// Grow memory by the specified amount of WebAssembly [`Pages`].
/// Grow memory by the specified amount of WebAssembly [`Pages`] and return
/// the previous memory size.
///
/// # Example
///
/// ```
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, Some(3), false)).unwrap();
/// let p = m.grow(2).unwrap();
///
/// assert_eq!(p, Pages(1));
/// assert_eq!(m.size(), Pages(3));
/// ```
///
/// # Errors
///
/// Returns an error if memory can't be grown by the specified amount
/// of pages.
///
/// ```should_panic
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, Some(1), false)).unwrap();
///
/// // This results in an error: `MemoryError::CouldNotGrow`.
/// let s = m.grow(1).unwrap();
/// ```
pub fn grow<IntoPages>(&self, delta: IntoPages) -> Result<Pages, MemoryError>
where
IntoPages: Into<Pages>,
Expand Down Expand Up @@ -155,7 +222,18 @@ impl Memory {
}
}

/// Returns whether or not these two globals refer to the same data.
/// Returns whether or not these two memories refer to the same data.
///
/// # Example
///
/// ```
/// # use wasmer::{Memory, MemoryType, Store, Value};
/// # let store = Store::default();
/// #
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
///
/// assert!(m.same(&m));
/// ```
pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.memory, &other.memory)
}
Expand Down

0 comments on commit 8245f36

Please sign in to comment.