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