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