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