wasmer/wasm_c_api/instance.rs
1use super::externals::{wasm_extern_t, wasm_extern_vec_t};
2use super::module::wasm_module_t;
3use super::store::{StoreRef, wasm_store_t};
4use super::trap::wasm_trap_t;
5use wasmer_api::{Extern, Instance, InstantiationError};
6
7/// Opaque type representing a WebAssembly instance.
8#[allow(non_camel_case_types)]
9pub struct wasm_instance_t {
10 pub(crate) store: StoreRef,
11 pub(crate) inner: Instance,
12}
13
14/// Creates a new instance from a WebAssembly module and a
15/// set of imports.
16///
17/// ## Errors
18///
19/// The function can fail in 2 ways:
20///
21/// 1. Link errors that happen when plugging the imports into the
22/// instance,
23/// 2. Runtime errors that happen when running the module `start`
24/// function.
25///
26/// The failure is stored in the `trap` argument; the program doesn't
27/// panic.
28///
29/// # Notes
30///
31/// The `store` argument is ignored. The store from the given module
32/// will be used.
33///
34/// # Example
35///
36/// See the module's documentation.
37#[unsafe(no_mangle)]
38pub unsafe extern "C" fn wasm_instance_new(
39 store: Option<&mut wasm_store_t>,
40 module: Option<&wasm_module_t>,
41 imports: Option<&wasm_extern_vec_t>,
42 trap: Option<&mut *mut wasm_trap_t>,
43) -> Option<Box<wasm_instance_t>> {
44 let store = store?;
45 let mut store_mut = unsafe { store.inner.store_mut() };
46 let module = module?;
47 let imports = imports?;
48
49 let wasm_module = &module.inner;
50 let module_imports = wasm_module.imports();
51 let module_import_count = module_imports.len();
52 let externs = imports
53 .as_slice()
54 .iter()
55 .map(|imp| Extern::from(imp.as_ref().unwrap().as_ref().clone()))
56 .take(module_import_count)
57 .collect::<Vec<Extern>>();
58
59 let instance = match Instance::new_by_index(&mut store_mut, wasm_module, &externs) {
60 Ok(instance) => instance,
61
62 Err(InstantiationError::Link(link_error)) => {
63 crate::error::update_last_error(link_error);
64
65 return None;
66 }
67
68 Err(InstantiationError::Start(runtime_error)) => {
69 if let Some(trap) = trap {
70 let this_trap: Box<wasm_trap_t> = Box::new(runtime_error.into());
71 *trap = Box::into_raw(this_trap);
72 }
73
74 return None;
75 }
76
77 Err(e @ InstantiationError::CpuFeature(_)) => {
78 crate::error::update_last_error(e);
79
80 return None;
81 }
82
83 Err(e @ InstantiationError::DifferentStores) => {
84 crate::error::update_last_error(e);
85
86 return None;
87 }
88
89 Err(e @ InstantiationError::DifferentArchOS) => {
90 crate::error::update_last_error(e);
91
92 return None;
93 }
94 };
95
96 Some(Box::new(wasm_instance_t {
97 store: store.inner.clone(),
98 inner: instance,
99 }))
100}
101
102/// Deletes an instance.
103///
104/// # Example
105///
106/// See [`wasm_instance_new`].
107#[unsafe(no_mangle)]
108pub unsafe extern "C" fn wasm_instance_delete(_instance: Option<Box<wasm_instance_t>>) {}
109
110/// Gets the exports of the instance.
111///
112/// # Example
113///
114/// ```rust
115/// # use inline_c::assert_c;
116/// # fn main() {
117/// # (assert_c! {
118/// # #include "tests/wasmer.h"
119/// #
120/// int main() {
121/// // Create the engine and the store.
122/// wasm_engine_t* engine = wasm_engine_new();
123/// wasm_store_t* store = wasm_store_new(engine);
124///
125/// // Create a WebAssembly module from a WAT definition.
126/// wasm_byte_vec_t wat;
127/// wasmer_byte_vec_new_from_string(
128/// &wat,
129/// "(module\n"
130/// " (func (export \"function\") (param i32 i64))\n"
131/// " (global (export \"global\") i32 (i32.const 7))\n"
132/// " (table (export \"table\") 0 funcref)\n"
133/// " (memory (export \"memory\") 1))"
134/// );
135/// wasm_byte_vec_t wasm;
136/// wat2wasm(&wat, &wasm);
137///
138/// // Create the module.
139/// wasm_module_t* module = wasm_module_new(store, &wasm);
140///
141/// // Instantiate the module.
142/// wasm_extern_vec_t imports = WASM_EMPTY_VEC;
143/// wasm_trap_t* trap = NULL;
144///
145/// wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &trap);
146/// assert(instance);
147///
148/// // Read the exports.
149/// wasm_extern_vec_t exports;
150/// wasm_instance_exports(instance, &exports);
151///
152/// // We have 4 of them.
153/// assert(exports.size == 4);
154///
155/// // The first one is a function. Use `wasm_extern_as_func`
156/// // to go further.
157/// assert(wasm_extern_kind(exports.data[0]) == WASM_EXTERN_FUNC);
158///
159/// // The second one is a global. Use `wasm_extern_as_global` to
160/// // go further.
161/// assert(wasm_extern_kind(exports.data[1]) == WASM_EXTERN_GLOBAL);
162///
163/// // The third one is a table. Use `wasm_extern_as_table` to
164/// // go further.
165/// assert(wasm_extern_kind(exports.data[2]) == WASM_EXTERN_TABLE);
166///
167/// // The fourth one is a memory. Use `wasm_extern_as_memory` to
168/// // go further.
169/// assert(wasm_extern_kind(exports.data[3]) == WASM_EXTERN_MEMORY);
170///
171/// // Free everything.
172/// wasm_extern_vec_delete(&exports);
173/// wasm_instance_delete(instance);
174/// wasm_module_delete(module);
175/// wasm_byte_vec_delete(&wasm);
176/// wasm_byte_vec_delete(&wat);
177/// wasm_store_delete(store);
178/// wasm_engine_delete(engine);
179///
180/// return 0;
181/// }
182/// # })
183/// # .success();
184/// # }
185/// ```
186///
187/// To go further:
188///
189/// * [`wasm_extern_as_func`][super::externals::wasm_extern_as_func],
190/// * [`wasm_extern_as_global`][super::externals::wasm_extern_as_global],
191/// * [`wasm_extern_as_table`][super::externals::wasm_extern_as_table],
192/// * [`wasm_extern_as_memory`][super::externals::wasm_extern_as_memory].
193#[unsafe(no_mangle)]
194pub unsafe extern "C" fn wasm_instance_exports(
195 instance: &wasm_instance_t,
196 // own
197 out: &mut wasm_extern_vec_t,
198) {
199 let original_instance = instance;
200 let instance = &instance.inner;
201 let extern_vec: Vec<Option<Box<wasm_extern_t>>> = instance
202 .exports
203 .iter()
204 .map(|(_name, r#extern)| {
205 Some(Box::new(wasm_extern_t::new(
206 original_instance.store.clone(),
207 r#extern.clone(),
208 )))
209 })
210 .collect();
211 out.set_buffer(extern_vec);
212}
213
214#[cfg(test)]
215mod tests {
216 use inline_c::assert_c;
217
218 #[allow(
219 unexpected_cfgs,
220 reason = "tools like cargo-llvm-coverage pass --cfg coverage"
221 )]
222 #[cfg_attr(coverage_nightly, coverage(off))]
223 #[test]
224 fn test_instance_new() {
225 (assert_c! {
226 #include "tests/wasmer.h"
227
228 // The `sum` host function implementation.
229 wasm_trap_t* sum_callback(
230 const wasm_val_vec_t* arguments,
231 wasm_val_vec_t* results
232 ) {
233 wasm_val_t sum = {
234 .kind = WASM_I32,
235 .of = { arguments->data[0].of.i32 + arguments->data[1].of.i32 },
236 };
237 results->data[0] = sum;
238
239 return NULL;
240 }
241
242 int main() {
243 // Create the engine and the store.
244 wasm_engine_t* engine = wasm_engine_new();
245 wasm_store_t* store = wasm_store_new(engine);
246
247 // Create a WebAssembly module from a WAT definition.
248 wasm_byte_vec_t wat;
249 wasmer_byte_vec_new_from_string(
250 &wat,
251 "(module\n"
252 " (import \"math\" \"sum\" (func $sum (param i32 i32) (result i32)))\n"
253 " (func (export \"add_one\") (param i32) (result i32)\n"
254 " local.get 0\n"
255 " i32.const 1\n"
256 " call $sum))"
257 );
258 wasm_byte_vec_t wasm;
259 wat2wasm(&wat, &wasm);
260
261 // Create the module.
262 wasm_module_t* module = wasm_module_new(store, &wasm);
263
264 assert(module);
265
266 // Prepare the imports.
267 wasm_functype_t* sum_type = wasm_functype_new_2_1(
268 wasm_valtype_new_i32(),
269 wasm_valtype_new_i32(),
270 wasm_valtype_new_i32()
271 );
272 wasm_func_t* sum_function = wasm_func_new(store, sum_type, sum_callback);
273 wasm_extern_t* externs[] = { wasm_func_as_extern(sum_function) };
274 wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
275
276 // Instantiate the module.
277 wasm_trap_t* trap = NULL;
278 wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &trap);
279
280 assert(instance);
281
282 // Run the exported function.
283 wasm_extern_vec_t exports;
284 wasm_instance_exports(instance, &exports);
285
286 assert(exports.size == 1);
287
288 const wasm_func_t* run_function = wasm_extern_as_func(exports.data[0]);
289
290 assert(run_function);
291
292 wasm_val_t arguments[1] = { WASM_I32_VAL(1) };
293 wasm_val_t results[1] = { WASM_INIT_VAL };
294
295 wasm_val_vec_t arguments_as_array = WASM_ARRAY_VEC(arguments);
296 wasm_val_vec_t results_as_array = WASM_ARRAY_VEC(results);
297
298 trap = wasm_func_call(run_function, &arguments_as_array, &results_as_array);
299
300 assert(trap == NULL);
301 assert(results[0].of.i32 == 2);
302
303 // Free everything.
304 wasm_extern_vec_delete(&exports);
305 wasm_instance_delete(instance);
306 wasm_func_delete(sum_function);
307 wasm_functype_delete(sum_type);
308 wasm_module_delete(module);
309 wasm_byte_vec_delete(&wasm);
310 wasm_byte_vec_delete(&wat);
311 wasm_store_delete(store);
312 wasm_engine_delete(engine);
313
314 return 0;
315 }
316 })
317 .success();
318 }
319}