1#![warn(missing_docs)]
4
5use ayaka_plugin::*;
6use std::{
7 collections::HashMap,
8 sync::{Arc, Mutex},
9};
10use wasmtime::*;
11
12unsafe fn mem_slice<'a, T: 'a>(
13 store: impl Into<StoreContext<'a, T>>,
14 memory: &Memory,
15 start: i32,
16 len: i32,
17) -> &'a [u8] {
18 memory
19 .data(store)
20 .get_unchecked(start as usize..)
21 .get_unchecked(..len as usize)
22}
23
24unsafe fn mem_slice_mut<'a, T: 'a>(
25 store: impl Into<StoreContextMut<'a, T>>,
26 memory: &Memory,
27 start: i32,
28 len: i32,
29) -> &'a mut [u8] {
30 memory
31 .data_mut(store)
32 .get_unchecked_mut(start as usize..)
33 .get_unchecked_mut(..len as usize)
34}
35
36type HostStore = Arc<Mutex<Store<()>>>;
37
38pub struct WasmtimeModule {
40 store: HostStore,
41 instance: Instance,
42 memory: Memory,
43 abi_free: TypedFunc<(i32, i32), ()>,
44 abi_alloc: TypedFunc<i32, i32>,
45}
46
47impl WasmtimeModule {
48 fn new(store: HostStore, module: &Module, linker: &wasmtime::Linker<()>) -> Result<Self> {
49 let mut inner_store = store.lock().unwrap();
50 let instance = linker.instantiate(inner_store.as_context_mut(), module)?;
51 let memory = instance
52 .get_memory(inner_store.as_context_mut(), MEMORY_NAME)
53 .ok_or_else(|| anyhow!("cannot get memory"))?;
54 let abi_free = instance.get_typed_func(inner_store.as_context_mut(), ABI_FREE_NAME)?;
55 let abi_alloc = instance.get_typed_func(inner_store.as_context_mut(), ABI_ALLOC_NAME)?;
56 drop(inner_store);
57 Ok(Self {
58 store,
59 instance,
60 memory,
61 abi_free,
62 abi_alloc,
63 })
64 }
65
66 fn call_impl<T>(
67 &self,
68 mut store: StoreContextMut<()>,
69 name: &str,
70 data: &[u8],
71 f: impl FnOnce(&[u8]) -> Result<T>,
72 ) -> Result<T> {
73 let func = self
74 .instance
75 .get_typed_func::<(i32, i32), u64>(&mut store, name)?;
76
77 let ptr = self.abi_alloc.call(&mut store, data.len() as i32)?;
78 unsafe {
79 mem_slice_mut(&mut store, &self.memory, ptr, data.len() as i32).copy_from_slice(data)
80 };
81
82 let res = func.call(&mut store, (data.len() as i32, ptr));
83
84 self.abi_free.call(&mut store, (ptr, data.len() as i32))?;
85
86 let res = res?;
87 let (len, res) = ((res >> 32) as i32, (res & 0xFFFFFFFF) as i32);
88
89 let res_data = unsafe { mem_slice(&store, &self.memory, res, len) };
90
91 let res_data = f(res_data);
92
93 self.abi_free.call(&mut store, (res, len))?;
94
95 let res_data = res_data?;
96 Ok(res_data)
97 }
98}
99
100impl RawModule for WasmtimeModule {
101 type Linker = WasmtimeLinker;
102
103 type LinkerHandle<'a> = WasmtimeLinkerHandle<'a>;
104
105 type Func = Func;
106
107 fn call<T>(&self, name: &str, data: &[u8], f: impl FnOnce(&[u8]) -> Result<T>) -> Result<T> {
108 self.call_impl(self.store.lock().unwrap().as_context_mut(), name, data, f)
109 }
110}
111
112pub struct WasmtimeLinker {
114 engine: Engine,
115 store: HostStore,
116 linker: wasmtime::Linker<()>,
117}
118
119impl ayaka_plugin::Linker<WasmtimeModule> for WasmtimeLinker {
120 type Config = ();
121
122 fn new(_: ()) -> Result<Self> {
123 let engine = Engine::default();
124 let store = Store::new(&engine, ());
125 let linker = wasmtime::Linker::new(&engine);
126 Ok(Self {
127 engine,
128 store: Arc::new(Mutex::new(store)),
129 linker,
130 })
131 }
132
133 fn create(&self, binary: &[u8]) -> Result<WasmtimeModule> {
134 let module = Module::new(&self.engine, binary)?;
135 let host = WasmtimeModule::new(self.store.clone(), &module, &self.linker)?;
136 Ok(host)
137 }
138
139 fn import(&mut self, ns: impl Into<String>, funcs: HashMap<String, Func>) -> Result<()> {
140 let ns = ns.into();
141 let store = self.store.lock().unwrap();
142 for (name, func) in funcs {
143 self.linker.define(store.as_context(), &ns, &name, func)?;
144 }
145 Ok(())
146 }
147
148 fn wrap_raw(
149 &self,
150 f: impl (Fn(WasmtimeLinkerHandle<'_>, i32, i32) -> Result<Vec<u8>>) + Send + Sync + 'static,
151 ) -> Func {
152 Func::wrap(
153 self.store.lock().unwrap().as_context_mut(),
154 move |mut store: Caller<()>, len: i32, data: i32| unsafe {
155 let memory = store
156 .get_export(MEMORY_NAME)
157 .ok_or_else(|| anyhow!("cannot get memory"))?
158 .into_memory()
159 .ok_or_else(|| anyhow!("memory is not Memory"))?;
160 let data = {
161 let store = store.as_context_mut();
162 let handle = WasmtimeLinkerHandle { store, memory };
163 f(handle, data, len)?
164 };
165 let abi_alloc = store
166 .get_export(ABI_ALLOC_NAME)
167 .ok_or_else(|| anyhow!("cannot get abi_alloc"))?
168 .into_func()
169 .ok_or_else(|| anyhow!("abi_alloc is not Func"))?
170 .typed::<i32, i32>(store.as_context())?;
171 let ptr = abi_alloc.call(store.as_context_mut(), data.len() as i32)?;
172 mem_slice_mut(store.as_context_mut(), &memory, ptr, data.len() as i32)
173 .copy_from_slice(&data);
174 Ok(((data.len() as u64) << 32) | (ptr as u64))
175 },
176 )
177 }
178}
179
180pub struct WasmtimeLinkerHandle<'a> {
182 store: StoreContextMut<'a, ()>,
183 memory: Memory,
184}
185
186impl<'a> LinkerHandle<'a, WasmtimeModule> for WasmtimeLinkerHandle<'a> {
187 fn call<T>(
188 &mut self,
189 m: &WasmtimeModule,
190 name: &str,
191 data: &[u8],
192 f: impl FnOnce(&[u8]) -> Result<T>,
193 ) -> Result<T> {
194 m.call_impl(self.store.as_context_mut(), name, data, f)
195 }
196
197 fn slice<T>(&self, start: i32, len: i32, f: impl FnOnce(&[u8]) -> T) -> T {
198 f(unsafe { mem_slice(self.store.as_context(), &self.memory, start, len) })
199 }
200
201 fn slice_mut<T>(&mut self, start: i32, len: i32, f: impl FnOnce(&mut [u8]) -> T) -> T {
202 f(unsafe { mem_slice_mut(self.store.as_context_mut(), &self.memory, start, len) })
203 }
204}