wasmer_c_api/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 wasmer_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 #[cfg(not(target_os = "windows"))]
217 use inline_c::assert_c;
218 #[cfg(target_os = "windows")]
219 use wasmer_inline_c::assert_c;
220
221 #[allow(
222 unexpected_cfgs,
223 reason = "tools like cargo-llvm-coverage pass --cfg coverage"
224 )]
225 #[cfg_attr(coverage_nightly, coverage(off))]
226 #[test]
227 fn test_instance_new() {
228 (assert_c! {
229 #include "tests/wasmer.h"
230
231 // The `sum` host function implementation.
232 wasm_trap_t* sum_callback(
233 const wasm_val_vec_t* arguments,
234 wasm_val_vec_t* results
235 ) {
236 wasm_val_t sum = {
237 .kind = WASM_I32,
238 .of = { arguments->data[0].of.i32 + arguments->data[1].of.i32 },
239 };
240 results->data[0] = sum;
241
242 return NULL;
243 }
244
245 int main() {
246 // Create the engine and the store.
247 wasm_engine_t* engine = wasm_engine_new();
248 wasm_store_t* store = wasm_store_new(engine);
249
250 // Create a WebAssembly module from a WAT definition.
251 wasm_byte_vec_t wat;
252 wasmer_byte_vec_new_from_string(
253 &wat,
254 "(module\n"
255 " (import \"math\" \"sum\" (func $sum (param i32 i32) (result i32)))\n"
256 " (func (export \"add_one\") (param i32) (result i32)\n"
257 " local.get 0\n"
258 " i32.const 1\n"
259 " call $sum))"
260 );
261 wasm_byte_vec_t wasm;
262 wat2wasm(&wat, &wasm);
263
264 // Create the module.
265 wasm_module_t* module = wasm_module_new(store, &wasm);
266
267 assert(module);
268
269 // Prepare the imports.
270 wasm_functype_t* sum_type = wasm_functype_new_2_1(
271 wasm_valtype_new_i32(),
272 wasm_valtype_new_i32(),
273 wasm_valtype_new_i32()
274 );
275 wasm_func_t* sum_function = wasm_func_new(store, sum_type, sum_callback);
276 wasm_extern_t* externs[] = { wasm_func_as_extern(sum_function) };
277 wasm_extern_vec_t imports = WASM_ARRAY_VEC(externs);
278
279 // Instantiate the module.
280 wasm_trap_t* trap = NULL;
281 wasm_instance_t* instance = wasm_instance_new(store, module, &imports, &trap);
282
283 assert(instance);
284
285 // Run the exported function.
286 wasm_extern_vec_t exports;
287 wasm_instance_exports(instance, &exports);
288
289 assert(exports.size == 1);
290
291 const wasm_func_t* run_function = wasm_extern_as_func(exports.data[0]);
292
293 assert(run_function);
294
295 wasm_val_t arguments[1] = { WASM_I32_VAL(1) };
296 wasm_val_t results[1] = { WASM_INIT_VAL };
297
298 wasm_val_vec_t arguments_as_array = WASM_ARRAY_VEC(arguments);
299 wasm_val_vec_t results_as_array = WASM_ARRAY_VEC(results);
300
301 trap = wasm_func_call(run_function, &arguments_as_array, &results_as_array);
302
303 assert(trap == NULL);
304 assert(results[0].of.i32 == 2);
305
306 // Free everything.
307 wasm_extern_vec_delete(&exports);
308 wasm_instance_delete(instance);
309 wasm_func_delete(sum_function);
310 wasm_functype_delete(sum_type);
311 wasm_module_delete(module);
312 wasm_byte_vec_delete(&wasm);
313 wasm_byte_vec_delete(&wat);
314 wasm_store_delete(store);
315 wasm_engine_delete(engine);
316
317 return 0;
318 }
319 })
320 .success();
321 }
322}