1 use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t};
2 use crate::{wasm_store_t, wasmtime_error_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     pub(crate) 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 externref(&self) -> wasmtime::ExternRef {
26         self.instance.externref()
27     }
28 }
29 
30 #[no_mangle]
31 pub unsafe extern "C" fn wasm_instance_new(
32     store: &wasm_store_t,
33     wasm_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 store = &store.store.borrow();
38     let module = &wasm_module.module.borrow();
39     if !Store::same(&store, module.store()) {
40         if let Some(result) = result {
41             let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
42             let trap = Box::new(wasm_trap_t::new(trap));
43             *result = Box::into_raw(trap);
44         }
45         return None;
46     }
47     let mut instance = ptr::null_mut();
48     let mut trap = ptr::null_mut();
49     let err = wasmtime_instance_new(
50         wasm_module,
51         imports,
52         wasm_module.imports.len(),
53         &mut instance,
54         &mut trap,
55     );
56     match err {
57         Some(err) => {
58             assert!(trap.is_null());
59             assert!(instance.is_null());
60             if let Some(result) = result {
61                 *result = Box::into_raw(err.to_trap());
62             }
63             None
64         }
65         None => {
66             if instance.is_null() {
67                 assert!(!trap.is_null());
68                 if let Some(result) = result {
69                     *result = trap;
70                 } else {
71                     drop(Box::from_raw(trap))
72                 }
73                 None
74             } else {
75                 assert!(trap.is_null());
76                 Some(Box::from_raw(instance))
77             }
78         }
79     }
80 }
81 
82 #[no_mangle]
83 pub unsafe extern "C" fn wasmtime_instance_new(
84     module: &wasm_module_t,
85     imports: *const Box<wasm_extern_t>,
86     num_imports: usize,
87     instance_ptr: &mut *mut wasm_instance_t,
88     trap_ptr: &mut *mut wasm_trap_t,
89 ) -> Option<Box<wasmtime_error_t>> {
90     _wasmtime_instance_new(
91         module,
92         std::slice::from_raw_parts(imports, num_imports),
93         instance_ptr,
94         trap_ptr,
95     )
96 }
97 
98 fn _wasmtime_instance_new(
99     module: &wasm_module_t,
100     imports: &[Box<wasm_extern_t>],
101     instance_ptr: &mut *mut wasm_instance_t,
102     trap_ptr: &mut *mut wasm_trap_t,
103 ) -> Option<Box<wasmtime_error_t>> {
104     let imports = imports
105         .iter()
106         .map(|import| match &import.which {
107             ExternHost::Func(e) => Extern::Func(e.borrow().clone()),
108             ExternHost::Table(e) => Extern::Table(e.borrow().clone()),
109             ExternHost::Global(e) => Extern::Global(e.borrow().clone()),
110             ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()),
111         })
112         .collect::<Vec<_>>();
113     let module = &module.module.borrow();
114     handle_instantiate(Instance::new(module, &imports), instance_ptr, trap_ptr)
115 }
116 
117 pub fn handle_instantiate(
118     instance: Result<Instance>,
119     instance_ptr: &mut *mut wasm_instance_t,
120     trap_ptr: &mut *mut wasm_trap_t,
121 ) -> Option<Box<wasmtime_error_t>> {
122     fn write<T>(ptr: &mut *mut T, val: T) {
123         *ptr = Box::into_raw(Box::new(val))
124     }
125 
126     match instance {
127         Ok(instance) => {
128             write(instance_ptr, wasm_instance_t::new(instance));
129             None
130         }
131         Err(e) => match e.downcast::<Trap>() {
132             Ok(trap) => {
133                 write(trap_ptr, wasm_trap_t::new(trap));
134                 None
135             }
136             Err(e) => Some(Box::new(e.into())),
137         },
138     }
139 }
140 
141 #[no_mangle]
142 pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wasm_extern_vec_t) {
143     let mut cache = instance.exports_cache.borrow_mut();
144     let exports = cache.get_or_insert_with(|| {
145         let instance = &instance.instance.borrow();
146         instance
147             .exports()
148             .map(|e| match e.into_extern() {
149                 Extern::Func(f) => ExternHost::Func(HostRef::new(f)),
150                 Extern::Global(f) => ExternHost::Global(HostRef::new(f)),
151                 Extern::Memory(f) => ExternHost::Memory(HostRef::new(f)),
152                 Extern::Table(f) => ExternHost::Table(HostRef::new(f)),
153             })
154             .collect()
155     });
156     let mut buffer = Vec::with_capacity(exports.len());
157     for e in exports {
158         let ext = Box::new(wasm_extern_t { which: e.clone() });
159         buffer.push(Some(ext));
160     }
161     out.set_buffer(buffer);
162 }
163