1 use crate::host_ref::HostRef;
2 use crate::{wasm_extern_t, wasm_extern_vec_t, wasm_module_t, wasm_trap_t};
3 use crate::{wasm_store_t, wasmtime_error_t, ExternHost};
4 use anyhow::Result;
5 use std::cell::RefCell;
6 use std::ptr;
7 use wasmtime::{Extern, Instance, Trap};
8 
9 #[repr(C)]
10 #[derive(Clone)]
11 pub struct wasm_instance_t {
12     pub(crate) instance: HostRef<Instance>,
13     exports_cache: RefCell<Option<Vec<ExternHost>>>,
14 }
15 
16 wasmtime_c_api_macros::declare_ref!(wasm_instance_t);
17 
18 impl wasm_instance_t {
19     pub(crate) fn new(instance: Instance) -> wasm_instance_t {
20         wasm_instance_t {
21             instance: HostRef::new(instance),
22             exports_cache: RefCell::new(None),
23         }
24     }
25 
26     fn externref(&self) -> wasmtime::ExternRef {
27         self.instance.clone().into()
28     }
29 }
30 
31 #[no_mangle]
32 pub unsafe extern "C" fn wasm_instance_new(
33     store: &wasm_store_t,
34     wasm_module: &wasm_module_t,
35     imports: *const Box<wasm_extern_t>,
36     result: Option<&mut *mut wasm_trap_t>,
37 ) -> Option<Box<wasm_instance_t>> {
38     let mut instance = ptr::null_mut();
39     let mut trap = ptr::null_mut();
40     let err = wasmtime_instance_new(
41         store,
42         wasm_module,
43         imports,
44         wasm_module.imports.len(),
45         &mut instance,
46         &mut trap,
47     );
48     match err {
49         Some(err) => {
50             assert!(trap.is_null());
51             assert!(instance.is_null());
52             if let Some(result) = result {
53                 *result = Box::into_raw(err.to_trap());
54             }
55             None
56         }
57         None => {
58             if instance.is_null() {
59                 assert!(!trap.is_null());
60                 if let Some(result) = result {
61                     *result = trap;
62                 } else {
63                     drop(Box::from_raw(trap))
64                 }
65                 None
66             } else {
67                 assert!(trap.is_null());
68                 Some(Box::from_raw(instance))
69             }
70         }
71     }
72 }
73 
74 #[no_mangle]
75 pub unsafe extern "C" fn wasmtime_instance_new(
76     store: &wasm_store_t,
77     module: &wasm_module_t,
78     imports: *const Box<wasm_extern_t>,
79     num_imports: usize,
80     instance_ptr: &mut *mut wasm_instance_t,
81     trap_ptr: &mut *mut wasm_trap_t,
82 ) -> Option<Box<wasmtime_error_t>> {
83     _wasmtime_instance_new(
84         store,
85         module,
86         std::slice::from_raw_parts(imports, num_imports),
87         instance_ptr,
88         trap_ptr,
89     )
90 }
91 
92 fn _wasmtime_instance_new(
93     store: &wasm_store_t,
94     module: &wasm_module_t,
95     imports: &[Box<wasm_extern_t>],
96     instance_ptr: &mut *mut wasm_instance_t,
97     trap_ptr: &mut *mut wasm_trap_t,
98 ) -> Option<Box<wasmtime_error_t>> {
99     let store = &store.store;
100     let imports = imports
101         .iter()
102         .map(|import| match &import.which {
103             ExternHost::Func(e) => Extern::Func(e.borrow().clone()),
104             ExternHost::Table(e) => Extern::Table(e.borrow().clone()),
105             ExternHost::Global(e) => Extern::Global(e.borrow().clone()),
106             ExternHost::Memory(e) => Extern::Memory(e.borrow().clone()),
107         })
108         .collect::<Vec<_>>();
109     let module = &module.module.borrow();
110     handle_instantiate(
111         Instance::new(store, module, &imports),
112         instance_ptr,
113         trap_ptr,
114     )
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