1#![no_std]
2
3#[macro_use]
4extern crate alloc;
5
6use alloc::string::ToString;
7use core::ptr;
8use wasmtime::{Config, Engine, Instance, Linker, Module, Result, Store, ensure};
9
10mod allocator;
11mod panic;
12
13#[cfg(feature = "wasi")]
14mod wasi;
15
16#[unsafe(no_mangle)]
22pub unsafe extern "C" fn run(
23 error_buf: *mut u8,
24 error_size: usize,
25 smoke_module: *const u8,
26 smoke_size: usize,
27 simple_add_module: *const u8,
28 simple_add_size: usize,
29 simple_host_fn_module: *const u8,
30 simple_host_fn_size: usize,
31 simple_floats_module: *const u8,
32 simple_floats_size: usize,
33) -> usize {
34 unsafe {
35 let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
36 let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
37 let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
38 let simple_host_fn =
39 core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
40 let simple_floats = core::slice::from_raw_parts(simple_floats_module, simple_floats_size);
41 match run_result(smoke, simple_add, simple_host_fn, simple_floats) {
42 Ok(()) => 0,
43 Err(e) => {
44 let msg = format!("{e:?}");
45 let len = buf.len().min(msg.len());
46 buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
47 len
48 }
49 }
50 }
51}
52
53fn run_result(
54 smoke_module: &[u8],
55 simple_add_module: &[u8],
56 simple_host_fn_module: &[u8],
57 simple_floats_module: &[u8],
58) -> Result<()> {
59 smoke(smoke_module)?;
60 simple_add(simple_add_module)?;
61 simple_host_fn(simple_host_fn_module)?;
62 simple_floats(simple_floats_module)?;
63 Ok(())
64}
65
66fn config() -> Config {
67 let mut config = Config::new();
68 let _ = &mut config;
69
70 #[cfg(target_arch = "x86_64")]
71 {
72 unsafe {
78 config.x86_float_abi_ok(true);
79 }
80
81 unsafe {
90 config.detect_host_feature(move |feature| {
91 let id = raw_cpuid::CpuId::new();
92 match feature {
93 "sse3" => Some(id.get_feature_info()?.has_sse3()),
94 "ssse3" => Some(id.get_feature_info()?.has_sse3()),
95 "sse4.1" => Some(id.get_feature_info()?.has_sse41()),
96 "sse4.2" => Some(id.get_feature_info()?.has_sse42()),
97 "fma" => Some(id.get_feature_info()?.has_fma()),
98 _ => None,
99 }
100 });
101 }
102 }
103
104 config
105}
106
107fn smoke(module: &[u8]) -> Result<()> {
108 let engine = Engine::new(&config())?;
109 let module = match deserialize(&engine, module)? {
110 Some(module) => module,
111 None => return Ok(()),
112 };
113 Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
114 Ok(())
115}
116
117fn simple_add(module: &[u8]) -> Result<()> {
118 let engine = Engine::new(&config())?;
119 let module = match deserialize(&engine, module)? {
120 Some(module) => module,
121 None => return Ok(()),
122 };
123 let mut store = Store::new(&engine, ());
124 let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
125 let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
126 ensure!(func.call(&mut store, (2, 3))? == 5);
127 Ok(())
128}
129
130fn simple_host_fn(module: &[u8]) -> Result<()> {
131 let engine = Engine::new(&config())?;
132 let module = match deserialize(&engine, module)? {
133 Some(module) => module,
134 None => return Ok(()),
135 };
136 let mut linker = Linker::<()>::new(&engine);
137 linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
138 let mut store = Store::new(&engine, ());
139 let instance = linker.instantiate(&mut store, &module)?;
140 let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?;
141 ensure!(func.call(&mut store, (2, 3, 4))? == 10);
142 Ok(())
143}
144
145fn simple_floats(module: &[u8]) -> Result<()> {
146 let engine = Engine::new(&config())?;
147 let module = match deserialize(&engine, module)? {
148 Some(module) => module,
149 None => return Ok(()),
150 };
151 let mut store = Store::new(&engine, ());
152 let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
153 let func = instance.get_typed_func::<(f32, f32), f32>(&mut store, "frob")?;
154 ensure!(func.call(&mut store, (1.4, 3.2))? == 5.);
155 Ok(())
156}
157
158fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> {
159 let result = if cfg!(feature = "custom") {
160 unsafe { Module::deserialize(engine, module) }
163 } else {
164 let memory_ptr = ptr::slice_from_raw_parts(module.as_ptr(), module.len());
171 let module_memory = ptr::NonNull::new(memory_ptr.cast_mut()).unwrap();
172 unsafe { Module::deserialize_raw(engine, module_memory) }
173 };
174 match result {
175 Ok(module) => Ok(Some(module)),
176 Err(e) => {
177 if !cfg!(feature = "custom")
183 && e.to_string()
184 .contains("requires virtual memory to be enabled")
185 {
186 Ok(None)
187 } else {
188 Err(e)
189 }
190 }
191 }
192}