15054d400SAlex Crichton #![no_std]
25054d400SAlex Crichton 
35054d400SAlex Crichton #[macro_use]
45054d400SAlex Crichton extern crate alloc;
55054d400SAlex Crichton 
6d3132c9dSAlex Crichton use alloc::string::ToString;
799efc20bSPaul Osborne use core::ptr;
8*41b081c1SNick Fitzgerald use wasmtime::{Config, Engine, Instance, Linker, Module, Result, Store, ensure};
9b81bb7a3SAlex Crichton 
10b81bb7a3SAlex Crichton mod allocator;
115054d400SAlex Crichton mod panic;
12b81bb7a3SAlex Crichton 
13b9b0ba49SPat Hickey #[cfg(feature = "wasi")]
14b9b0ba49SPat Hickey mod wasi;
15b9b0ba49SPat Hickey 
165054d400SAlex Crichton /// Entrypoint of this embedding.
175054d400SAlex Crichton ///
185054d400SAlex Crichton /// This takes a number of parameters which are the precompiled module AOT
195054d400SAlex Crichton /// images that are run for each of the various tests below. The first parameter
205054d400SAlex Crichton /// is also where to put an error string, if any, if anything fails.
21ae84e6edSAlex Crichton #[unsafe(no_mangle)]
run( error_buf: *mut u8, error_size: usize, smoke_module: *const u8, smoke_size: usize, simple_add_module: *const u8, simple_add_size: usize, simple_host_fn_module: *const u8, simple_host_fn_size: usize, simple_floats_module: *const u8, simple_floats_size: usize, ) -> usize225054d400SAlex Crichton pub unsafe extern "C" fn run(
235054d400SAlex Crichton     error_buf: *mut u8,
245054d400SAlex Crichton     error_size: usize,
255054d400SAlex Crichton     smoke_module: *const u8,
265054d400SAlex Crichton     smoke_size: usize,
275054d400SAlex Crichton     simple_add_module: *const u8,
285054d400SAlex Crichton     simple_add_size: usize,
295054d400SAlex Crichton     simple_host_fn_module: *const u8,
305054d400SAlex Crichton     simple_host_fn_size: usize,
31c7dc2d52SAlex Crichton     simple_floats_module: *const u8,
32c7dc2d52SAlex Crichton     simple_floats_size: usize,
335054d400SAlex Crichton ) -> usize {
34073aedabSAlex Crichton     unsafe {
355054d400SAlex Crichton         let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
365054d400SAlex Crichton         let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
375054d400SAlex Crichton         let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
38073aedabSAlex Crichton         let simple_host_fn =
39073aedabSAlex Crichton             core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
40c7dc2d52SAlex Crichton         let simple_floats = core::slice::from_raw_parts(simple_floats_module, simple_floats_size);
41c7dc2d52SAlex Crichton         match run_result(smoke, simple_add, simple_host_fn, simple_floats) {
42b81bb7a3SAlex Crichton             Ok(()) => 0,
43b81bb7a3SAlex Crichton             Err(e) => {
44b81bb7a3SAlex Crichton                 let msg = format!("{e:?}");
45b81bb7a3SAlex Crichton                 let len = buf.len().min(msg.len());
46b81bb7a3SAlex Crichton                 buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
47b81bb7a3SAlex Crichton                 len
48b81bb7a3SAlex Crichton             }
49b81bb7a3SAlex Crichton         }
50b81bb7a3SAlex Crichton     }
51073aedabSAlex Crichton }
52b81bb7a3SAlex Crichton 
run_result( smoke_module: &[u8], simple_add_module: &[u8], simple_host_fn_module: &[u8], simple_floats_module: &[u8], ) -> Result<()>535054d400SAlex Crichton fn run_result(
545054d400SAlex Crichton     smoke_module: &[u8],
555054d400SAlex Crichton     simple_add_module: &[u8],
565054d400SAlex Crichton     simple_host_fn_module: &[u8],
57c7dc2d52SAlex Crichton     simple_floats_module: &[u8],
585054d400SAlex Crichton ) -> Result<()> {
595054d400SAlex Crichton     smoke(smoke_module)?;
605054d400SAlex Crichton     simple_add(simple_add_module)?;
615054d400SAlex Crichton     simple_host_fn(simple_host_fn_module)?;
62c7dc2d52SAlex Crichton     simple_floats(simple_floats_module)?;
63b81bb7a3SAlex Crichton     Ok(())
64b81bb7a3SAlex Crichton }
65b81bb7a3SAlex Crichton 
config() -> Config66c7dc2d52SAlex Crichton fn config() -> Config {
67c7dc2d52SAlex Crichton     let mut config = Config::new();
68c7dc2d52SAlex Crichton     let _ = &mut config;
69c7dc2d52SAlex Crichton 
70c7dc2d52SAlex Crichton     #[cfg(target_arch = "x86_64")]
71c7dc2d52SAlex Crichton     {
72c7dc2d52SAlex Crichton         // This example runs in a Linux process where it's valid to use
73c7dc2d52SAlex Crichton         // floating point registers. Additionally sufficient x86 features are
74c7dc2d52SAlex Crichton         // enabled during compilation to avoid float-related libcalls. Thus
75c7dc2d52SAlex Crichton         // despite the host being configured for "soft float" it should be
76c7dc2d52SAlex Crichton         // valid to turn this on.
77c7dc2d52SAlex Crichton         unsafe {
78c7dc2d52SAlex Crichton             config.x86_float_abi_ok(true);
79c7dc2d52SAlex Crichton         }
80c7dc2d52SAlex Crichton 
81c7dc2d52SAlex Crichton         // To make the float ABI above OK it requires CPU features above
82c7dc2d52SAlex Crichton         // baseline to be enabled. Wasmtime needs to be able to check to ensure
83c7dc2d52SAlex Crichton         // that the feature is actually supplied at runtime, but a default check
84c7dc2d52SAlex Crichton         // isn't possible in no_std. For x86_64 we can use the cpuid instruction
85c7dc2d52SAlex Crichton         // bound through an external crate.
86c7dc2d52SAlex Crichton         //
87d55a5c8bSgeogrego         // Note that CPU support for these features has existed since 2013
88c7dc2d52SAlex Crichton         // (Haswell) on Intel chips and 2012 (Piledriver) on AMD chips.
89c7dc2d52SAlex Crichton         unsafe {
90c7dc2d52SAlex Crichton             config.detect_host_feature(move |feature| {
91c7dc2d52SAlex Crichton                 let id = raw_cpuid::CpuId::new();
92c7dc2d52SAlex Crichton                 match feature {
93c7dc2d52SAlex Crichton                     "sse3" => Some(id.get_feature_info()?.has_sse3()),
94c7dc2d52SAlex Crichton                     "ssse3" => Some(id.get_feature_info()?.has_sse3()),
95c7dc2d52SAlex Crichton                     "sse4.1" => Some(id.get_feature_info()?.has_sse41()),
96c7dc2d52SAlex Crichton                     "sse4.2" => Some(id.get_feature_info()?.has_sse42()),
97c7dc2d52SAlex Crichton                     "fma" => Some(id.get_feature_info()?.has_fma()),
98c7dc2d52SAlex Crichton                     _ => None,
99c7dc2d52SAlex Crichton                 }
100c7dc2d52SAlex Crichton             });
101c7dc2d52SAlex Crichton         }
102c7dc2d52SAlex Crichton     }
103c7dc2d52SAlex Crichton 
104c7dc2d52SAlex Crichton     config
105c7dc2d52SAlex Crichton }
106c7dc2d52SAlex Crichton 
smoke(module: &[u8]) -> Result<()>1075054d400SAlex Crichton fn smoke(module: &[u8]) -> Result<()> {
108c7dc2d52SAlex Crichton     let engine = Engine::new(&config())?;
109d3132c9dSAlex Crichton     let module = match deserialize(&engine, module)? {
110d3132c9dSAlex Crichton         Some(module) => module,
111d3132c9dSAlex Crichton         None => return Ok(()),
112d3132c9dSAlex Crichton     };
113b81bb7a3SAlex Crichton     Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
114b81bb7a3SAlex Crichton     Ok(())
115b81bb7a3SAlex Crichton }
116b81bb7a3SAlex Crichton 
simple_add(module: &[u8]) -> Result<()>1175054d400SAlex Crichton fn simple_add(module: &[u8]) -> Result<()> {
118c7dc2d52SAlex Crichton     let engine = Engine::new(&config())?;
119d3132c9dSAlex Crichton     let module = match deserialize(&engine, module)? {
120d3132c9dSAlex Crichton         Some(module) => module,
121d3132c9dSAlex Crichton         None => return Ok(()),
122d3132c9dSAlex Crichton     };
123b81bb7a3SAlex Crichton     let mut store = Store::new(&engine, ());
1245054d400SAlex Crichton     let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
125b81bb7a3SAlex Crichton     let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
126c7dc2d52SAlex Crichton     ensure!(func.call(&mut store, (2, 3))? == 5);
127b81bb7a3SAlex Crichton     Ok(())
128b81bb7a3SAlex Crichton }
129b81bb7a3SAlex Crichton 
simple_host_fn(module: &[u8]) -> Result<()>1305054d400SAlex Crichton fn simple_host_fn(module: &[u8]) -> Result<()> {
131c7dc2d52SAlex Crichton     let engine = Engine::new(&config())?;
132d3132c9dSAlex Crichton     let module = match deserialize(&engine, module)? {
133d3132c9dSAlex Crichton         Some(module) => module,
134d3132c9dSAlex Crichton         None => return Ok(()),
135d3132c9dSAlex Crichton     };
136b81bb7a3SAlex Crichton     let mut linker = Linker::<()>::new(&engine);
137b81bb7a3SAlex Crichton     linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
138b81bb7a3SAlex Crichton     let mut store = Store::new(&engine, ());
139b81bb7a3SAlex Crichton     let instance = linker.instantiate(&mut store, &module)?;
140b81bb7a3SAlex Crichton     let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?;
141c7dc2d52SAlex Crichton     ensure!(func.call(&mut store, (2, 3, 4))? == 10);
142c7dc2d52SAlex Crichton     Ok(())
143c7dc2d52SAlex Crichton }
144c7dc2d52SAlex Crichton 
simple_floats(module: &[u8]) -> Result<()>145c7dc2d52SAlex Crichton fn simple_floats(module: &[u8]) -> Result<()> {
146c7dc2d52SAlex Crichton     let engine = Engine::new(&config())?;
147c7dc2d52SAlex Crichton     let module = match deserialize(&engine, module)? {
148c7dc2d52SAlex Crichton         Some(module) => module,
149c7dc2d52SAlex Crichton         None => return Ok(()),
150c7dc2d52SAlex Crichton     };
151c7dc2d52SAlex Crichton     let mut store = Store::new(&engine, ());
152c7dc2d52SAlex Crichton     let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
153c7dc2d52SAlex Crichton     let func = instance.get_typed_func::<(f32, f32), f32>(&mut store, "frob")?;
154c7dc2d52SAlex Crichton     ensure!(func.call(&mut store, (1.4, 3.2))? == 5.);
155b81bb7a3SAlex Crichton     Ok(())
156b81bb7a3SAlex Crichton }
157d3132c9dSAlex Crichton 
deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>>158d3132c9dSAlex Crichton fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> {
159dcfb6761SAlex Crichton     let result = if cfg!(feature = "custom") {
160dcfb6761SAlex Crichton         // If a custom virtual memory system is in use use the raw `deserialize`
161dcfb6761SAlex Crichton         // API to let Wasmtime handle publishing the executable and such.
162dcfb6761SAlex Crichton         unsafe { Module::deserialize(engine, module) }
163dcfb6761SAlex Crichton     } else {
164dcfb6761SAlex Crichton         // NOTE: deserialize_raw avoids creating a copy of the module code. See
165dcfb6761SAlex Crichton         // the safety notes before using in your embedding.
166dcfb6761SAlex Crichton         //
167dcfb6761SAlex Crichton         // Also note that this will only work for native code with a custom code
168dcfb6761SAlex Crichton         // publisher which isn't configured in this example. Such custom code
169dcfb6761SAlex Crichton         // publisher will need to handle making this executable for example.
17099efc20bSPaul Osborne         let memory_ptr = ptr::slice_from_raw_parts(module.as_ptr(), module.len());
17199efc20bSPaul Osborne         let module_memory = ptr::NonNull::new(memory_ptr.cast_mut()).unwrap();
172dcfb6761SAlex Crichton         unsafe { Module::deserialize_raw(engine, module_memory) }
173dcfb6761SAlex Crichton     };
174dcfb6761SAlex Crichton     match result {
175d3132c9dSAlex Crichton         Ok(module) => Ok(Some(module)),
176d3132c9dSAlex Crichton         Err(e) => {
1777f9049b9SAlex Crichton             // Currently if custom signals/virtual memory are disabled then this
1787f9049b9SAlex Crichton             // example is expected to fail to load since loading native code
1797f9049b9SAlex Crichton             // requires virtual memory. In the future this will go away as when
180d3132c9dSAlex Crichton             // signals-based-traps is disabled then that means that the
181d3132c9dSAlex Crichton             // interpreter should be used which should work here.
1827f9049b9SAlex Crichton             if !cfg!(feature = "custom")
183d3132c9dSAlex Crichton                 && e.to_string()
184d3132c9dSAlex Crichton                     .contains("requires virtual memory to be enabled")
185d3132c9dSAlex Crichton             {
186d3132c9dSAlex Crichton                 Ok(None)
187d3132c9dSAlex Crichton             } else {
188d3132c9dSAlex Crichton                 Err(e)
189d3132c9dSAlex Crichton             }
190d3132c9dSAlex Crichton         }
191d3132c9dSAlex Crichton     }
192d3132c9dSAlex Crichton }
193