1 use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t};
2 use crate::{wasm_store_t, ExternHost};
3 use anyhow::Result;
4 use std::cell::RefCell;
5 use std::ptr;
6 use wasmtime::{Extern, HostRef, Instance, Store, Trap};
7 
8 #[repr(C)]
9 #[derive(Clone)]
10 pub struct wasm_instance_t {
11     pub(crate) instance: HostRef<Instance>,
12     exports_cache: RefCell<Option<Vec<ExternHost>>>,
13 }
14 
15 wasmtime_c_api_macros::declare_ref!(wasm_instance_t);
16 
17 impl wasm_instance_t {
18     fn new(instance: Instance) -> wasm_instance_t {
19         wasm_instance_t {
20             instance: HostRef::new(instance),
21             exports_cache: RefCell::new(None),
22         }
23     }
24 
25     fn anyref(&self) -> wasmtime::AnyRef {
26         self.instance.anyref()
27     }
28 }
29 
30 #[no_mangle]
31 pub unsafe extern "C" fn wasm_instance_new(
32     store: &wasm_store_t,
33     module: &wasm_module_t,
34     imports: *const Box<wasm_extern_t>,
35     result: Option<&mut *mut wasm_trap_t>,
36 ) -> Option<Box<wasm_instance_t>> {
37     let mut externs: Vec<Extern> = Vec::with_capacity((*module).imports.len());
38     for i in 0..(*module).imports.len() {
39         let import = &*imports.add(i);
40         externs.push(match &import.which {
41             ExternHost::Func(e) => Extern::Func(e.borrow().clone()),
42             ExternHost::Table(e) => Extern::Table(e.borrow().clone()),
43             ExternHost::Global(e) => Extern::Global(e.borrow().clone()),
44             ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()),
45         });
46     }
47     let store = &(*store).store.borrow();
48     let module = &(*module).module.borrow();
49     if !Store::same(&store, module.store()) {
50         if let Some(result) = result {
51             let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
52             let trap = Box::new(wasm_trap_t {
53                 trap: HostRef::new(trap),
54             });
55             *result = Box::into_raw(trap);
56         }
57         return None;
58     }
59     handle_instantiate(Instance::new(module, &externs), result)
60 }
61 
62 pub fn handle_instantiate(
63     instance: Result<Instance>,
64     result: Option<&mut *mut wasm_trap_t>,
65 ) -> Option<Box<wasm_instance_t>> {
66     match instance {
67         Ok(instance) => {
68             if let Some(result) = result {
69                 *result = ptr::null_mut();
70             }
71             Some(Box::new(wasm_instance_t::new(instance)))
72         }
73         Err(trap) => {
74             if let Some(result) = result {
75                 let trap = match trap.downcast::<Trap>() {
76                     Ok(trap) => trap,
77                     Err(e) => Trap::new(format!("{:?}", e)),
78                 };
79                 let trap = Box::new(wasm_trap_t {
80                     trap: HostRef::new(trap),
81                 });
82                 *result = Box::into_raw(trap);
83             }
84             None
85         }
86     }
87 }
88 
89 #[no_mangle]
90 pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wasm_extern_vec_t) {
91     let mut cache = instance.exports_cache.borrow_mut();
92     let exports = cache.get_or_insert_with(|| {
93         let instance = &instance.instance.borrow();
94         instance
95             .exports()
96             .iter()
97             .map(|e| match e {
98                 Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())),
99                 Extern::Global(f) => ExternHost::Global(HostRef::new(f.clone())),
100                 Extern::Memory(f) => ExternHost::Memory(HostRef::new(f.clone())),
101                 Extern::Table(f) => ExternHost::Table(HostRef::new(f.clone())),
102             })
103             .collect()
104     });
105     let mut buffer = Vec::with_capacity(exports.len());
106     for e in exports {
107         let ext = Box::new(wasm_extern_t { which: e.clone() });
108         buffer.push(Some(ext));
109     }
110     out.set_buffer(buffer);
111 }
112