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