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}