Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/examples/min-platform/embedding/src/lib.rs
2450 views
1
#![no_std]
2
3
#[macro_use]
4
extern crate alloc;
5
6
use alloc::string::ToString;
7
use anyhow::{Result, ensure};
8
use core::ptr;
9
use wasmtime::{Config, Engine, Instance, Linker, Module, Store};
10
11
mod allocator;
12
mod panic;
13
14
#[cfg(feature = "wasi")]
15
mod 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)]
23
pub 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
simple_floats_module: *const u8,
33
simple_floats_size: usize,
34
) -> usize {
35
unsafe {
36
let buf = core::slice::from_raw_parts_mut(error_buf, error_size);
37
let smoke = core::slice::from_raw_parts(smoke_module, smoke_size);
38
let simple_add = core::slice::from_raw_parts(simple_add_module, simple_add_size);
39
let simple_host_fn =
40
core::slice::from_raw_parts(simple_host_fn_module, simple_host_fn_size);
41
let simple_floats = core::slice::from_raw_parts(simple_floats_module, simple_floats_size);
42
match run_result(smoke, simple_add, simple_host_fn, simple_floats) {
43
Ok(()) => 0,
44
Err(e) => {
45
let msg = format!("{e:?}");
46
let len = buf.len().min(msg.len());
47
buf[..len].copy_from_slice(&msg.as_bytes()[..len]);
48
len
49
}
50
}
51
}
52
}
53
54
fn run_result(
55
smoke_module: &[u8],
56
simple_add_module: &[u8],
57
simple_host_fn_module: &[u8],
58
simple_floats_module: &[u8],
59
) -> Result<()> {
60
smoke(smoke_module)?;
61
simple_add(simple_add_module)?;
62
simple_host_fn(simple_host_fn_module)?;
63
simple_floats(simple_floats_module)?;
64
Ok(())
65
}
66
67
fn config() -> Config {
68
let mut config = Config::new();
69
let _ = &mut config;
70
71
#[cfg(target_arch = "x86_64")]
72
{
73
// This example runs in a Linux process where it's valid to use
74
// floating point registers. Additionally sufficient x86 features are
75
// enabled during compilation to avoid float-related libcalls. Thus
76
// despite the host being configured for "soft float" it should be
77
// valid to turn this on.
78
unsafe {
79
config.x86_float_abi_ok(true);
80
}
81
82
// To make the float ABI above OK it requires CPU features above
83
// baseline to be enabled. Wasmtime needs to be able to check to ensure
84
// that the feature is actually supplied at runtime, but a default check
85
// isn't possible in no_std. For x86_64 we can use the cpuid instruction
86
// bound through an external crate.
87
//
88
// Note that CPU support for these features has existed since 2013
89
// (Haswell) on Intel chips and 2012 (Piledriver) on AMD chips.
90
unsafe {
91
config.detect_host_feature(move |feature| {
92
let id = raw_cpuid::CpuId::new();
93
match feature {
94
"sse3" => Some(id.get_feature_info()?.has_sse3()),
95
"ssse3" => Some(id.get_feature_info()?.has_sse3()),
96
"sse4.1" => Some(id.get_feature_info()?.has_sse41()),
97
"sse4.2" => Some(id.get_feature_info()?.has_sse42()),
98
"fma" => Some(id.get_feature_info()?.has_fma()),
99
_ => None,
100
}
101
});
102
}
103
}
104
105
config
106
}
107
108
fn smoke(module: &[u8]) -> Result<()> {
109
let engine = Engine::new(&config())?;
110
let module = match deserialize(&engine, module)? {
111
Some(module) => module,
112
None => return Ok(()),
113
};
114
Instance::new(&mut Store::new(&engine, ()), &module, &[])?;
115
Ok(())
116
}
117
118
fn simple_add(module: &[u8]) -> Result<()> {
119
let engine = Engine::new(&config())?;
120
let module = match deserialize(&engine, module)? {
121
Some(module) => module,
122
None => return Ok(()),
123
};
124
let mut store = Store::new(&engine, ());
125
let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
126
let func = instance.get_typed_func::<(u32, u32), u32>(&mut store, "add")?;
127
ensure!(func.call(&mut store, (2, 3))? == 5);
128
Ok(())
129
}
130
131
fn simple_host_fn(module: &[u8]) -> Result<()> {
132
let engine = Engine::new(&config())?;
133
let module = match deserialize(&engine, module)? {
134
Some(module) => module,
135
None => return Ok(()),
136
};
137
let mut linker = Linker::<()>::new(&engine);
138
linker.func_wrap("host", "multiply", |a: u32, b: u32| a.saturating_mul(b))?;
139
let mut store = Store::new(&engine, ());
140
let instance = linker.instantiate(&mut store, &module)?;
141
let func = instance.get_typed_func::<(u32, u32, u32), u32>(&mut store, "add_and_mul")?;
142
ensure!(func.call(&mut store, (2, 3, 4))? == 10);
143
Ok(())
144
}
145
146
fn simple_floats(module: &[u8]) -> Result<()> {
147
let engine = Engine::new(&config())?;
148
let module = match deserialize(&engine, module)? {
149
Some(module) => module,
150
None => return Ok(()),
151
};
152
let mut store = Store::new(&engine, ());
153
let instance = Linker::new(&engine).instantiate(&mut store, &module)?;
154
let func = instance.get_typed_func::<(f32, f32), f32>(&mut store, "frob")?;
155
ensure!(func.call(&mut store, (1.4, 3.2))? == 5.);
156
Ok(())
157
}
158
159
fn deserialize(engine: &Engine, module: &[u8]) -> Result<Option<Module>> {
160
let result = if cfg!(feature = "custom") {
161
// If a custom virtual memory system is in use use the raw `deserialize`
162
// API to let Wasmtime handle publishing the executable and such.
163
unsafe { Module::deserialize(engine, module) }
164
} else {
165
// NOTE: deserialize_raw avoids creating a copy of the module code. See
166
// the safety notes before using in your embedding.
167
//
168
// Also note that this will only work for native code with a custom code
169
// publisher which isn't configured in this example. Such custom code
170
// publisher will need to handle making this executable for example.
171
let memory_ptr = ptr::slice_from_raw_parts(module.as_ptr(), module.len());
172
let module_memory = ptr::NonNull::new(memory_ptr.cast_mut()).unwrap();
173
unsafe { Module::deserialize_raw(engine, module_memory) }
174
};
175
match result {
176
Ok(module) => Ok(Some(module)),
177
Err(e) => {
178
// Currently if custom signals/virtual memory are disabled then this
179
// example is expected to fail to load since loading native code
180
// requires virtual memory. In the future this will go away as when
181
// signals-based-traps is disabled then that means that the
182
// interpreter should be used which should work here.
183
if !cfg!(feature = "custom")
184
&& e.to_string()
185
.contains("requires virtual memory to be enabled")
186
{
187
Ok(None)
188
} else {
189
Err(e)
190
}
191
}
192
}
193
}
194
195