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