embedding/
lib.rs

1#![no_std]
2
3#[macro_use]
4extern crate alloc;
5
6use alloc::string::ToString;
7use anyhow::Result;
8use core::ptr;
9use wasmtime::{Engine, Instance, Linker, Module, Store};
10
11mod allocator;
12mod panic;
13
14#[cfg(feature = "wasi")]
15mod wasi;
16
17/// Entrypoint of this embedding.
18///
19/// This takes a number of parameters which are the precompiled module AOT
20/// images that are run for each of the various tests below. The first parameter
21/// is also where to put an error string, if any, if anything fails.
22#[unsafe(no_mangle)]
23pub unsafe extern "C" fn run(
24    error_buf: *mut u8,
25    error_size: usize,
26    smoke_module: *const u8,
27    smoke_size: usize,
28    simple_add_module: *const u8,
29    simple_add_size: usize,
30    simple_host_fn_module: *const u8,
31    simple_host_fn_size: usize,
32) -> usize {
33    let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
34    let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
35    let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
36    let simple_host_fn = core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
37    match run_result(smoke, simple_add, simple_host_fn) {
38        Ok(()) => 0,
39        Err(e) => {
40            let msg = format!("{e:?}");
41            let len = buf.len().min(msg.len());
42            buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
43            len
44        }
45    }
46}
47
48fn run_result(
49    smoke_module: &[u8],
50    simple_add_module: &[u8],
51    simple_host_fn_module: &[u8],
52) -> Result<()> {
53    smoke(smoke_module)?;
54    simple_add(simple_add_module)?;
55    simple_host_fn(simple_host_fn_module)?;
56    Ok(())
57}
58
59fn smoke(module: &[u8]) -> Result<()> {
60    let engine = Engine::default();
61    let module = match deserialize(&engine, module)? {
62        Some(module) => module,
63        None => return Ok(()),
64    };
65    Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
66    Ok(())
67}
68
69fn simple_add(module: &[u8]) -> Result<()> {
70    let engine = Engine::default();
71    let module = match deserialize(&engine, module)? {
72        Some(module) => module,
73        None => return Ok(()),
74    };
75    let mut store = Store::new(&engine, ());
76    let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
77    let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
78    assert_eq!(func.call(&mut store, (2, 3))?, 5);
79    Ok(())
80}
81
82fn simple_host_fn(module: &[u8]) -> Result<()> {
83    let engine = Engine::default();
84    let module = match deserialize(&engine, module)? {
85        Some(module) => module,
86        None => return Ok(()),
87    };
88    let mut linker = Linker::<()>::new(&engine);
89    linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
90    let mut store = Store::new(&engine, ());
91    let instance = linker.instantiate(&mut store, &module)?;
92    let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?;
93    assert_eq!(func.call(&mut store, (2, 3, 4))?, 10);
94    Ok(())
95}
96
97fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> {
98    // NOTE: deserialize_raw avoids creating a copy of the module code.  See the
99    // safety notes before using in your embedding.
100    let memory_ptr = ptr::slice_from_raw_parts(module.as_ptr(), module.len());
101    let module_memory = ptr::NonNull::new(memory_ptr.cast_mut()).unwrap();
102    match unsafe { Module::deserialize_raw(engine, module_memory) } {
103        Ok(module) => Ok(Some(module)),
104        Err(e) => {
105            // Currently if custom signals/virtual memory are disabled then this
106            // example is expected to fail to load since loading native code
107            // requires virtual memory. In the future this will go away as when
108            // signals-based-traps is disabled then that means that the
109            // interpreter should be used which should work here.
110            if !cfg!(feature = "custom")
111                && e.to_string()
112                    .contains("requires virtual memory to be enabled")
113            {
114                Ok(None)
115            } else {
116                Err(e)
117            }
118        }
119    }
120}