linera_witty/runtime/wasmer/
mod.rs1mod export_function;
7mod function;
8mod memory;
9mod parameters;
10mod results;
11
12use std::sync::{Arc, Mutex, MutexGuard, OnceLock};
13
14pub use wasmer::FunctionEnvMut;
15use wasmer::{
16 AsStoreMut, AsStoreRef, Engine, Extern, FunctionEnv, Imports, InstantiationError, Memory,
17 Module, Store, StoreMut, StoreObjects, StoreRef,
18};
19
20pub use self::{parameters::WasmerParameters, results::WasmerResults};
21use super::traits::{Instance, Runtime};
22
23pub struct Wasmer;
25
26impl Runtime for Wasmer {
27 type Export = Extern;
28 type Memory = Memory;
29}
30
31pub struct InstanceBuilder<UserData> {
33 store: Store,
34 imports: Imports,
35 environment: Environment<UserData>,
36}
37
38impl<UserData: 'static> InstanceBuilder<UserData> {
39 pub fn new(engine: Engine, user_data: UserData) -> Self {
41 InstanceBuilder {
42 store: Store::new(engine),
43 imports: Imports::default(),
44 environment: Environment::new(user_data),
45 }
46 }
47
48 pub fn store(&self) -> &Store {
50 &self.store
51 }
52
53 pub fn environment(&mut self) -> FunctionEnv<Environment<UserData>> {
57 FunctionEnv::new(&mut self.store, self.environment.clone())
58 }
59
60 pub fn define(&mut self, namespace: &str, name: &str, value: impl Into<Extern>) {
62 self.imports.define(namespace, name, value);
63 }
64
65 #[allow(clippy::result_large_err)]
67 pub fn instantiate(
68 mut self,
69 module: &Module,
70 ) -> Result<EntrypointInstance<UserData>, InstantiationError> {
71 let instance = wasmer::Instance::new(&mut self.store, module, &self.imports)?;
72 self.environment
73 .exports
74 .set(instance.exports.clone())
75 .expect("Environment already initialized");
76 Ok(EntrypointInstance {
77 store: self.store,
78 instance,
79 instance_slot: self.environment,
80 })
81 }
82}
83
84impl<UserData> AsStoreRef for InstanceBuilder<UserData> {
85 fn as_store_ref(&self) -> StoreRef<'_> {
86 self.store.as_store_ref()
87 }
88}
89
90impl<UserData> AsStoreMut for InstanceBuilder<UserData> {
91 fn as_store_mut(&mut self) -> StoreMut<'_> {
92 self.store.as_store_mut()
93 }
94
95 fn objects_mut(&mut self) -> &mut StoreObjects {
96 self.store.objects_mut()
97 }
98}
99
100pub struct EntrypointInstance<UserData> {
102 store: Store,
103 instance: wasmer::Instance,
104 instance_slot: Environment<UserData>,
105}
106
107impl<UserData> AsStoreRef for EntrypointInstance<UserData> {
108 fn as_store_ref(&self) -> StoreRef<'_> {
109 self.store.as_store_ref()
110 }
111}
112
113impl<UserData> AsStoreMut for EntrypointInstance<UserData> {
114 fn as_store_mut(&mut self) -> StoreMut<'_> {
115 self.store.as_store_mut()
116 }
117
118 fn objects_mut(&mut self) -> &mut StoreObjects {
119 self.store.objects_mut()
120 }
121}
122
123impl<UserData> EntrypointInstance<UserData> {
124 pub fn as_store_and_instance_mut(&mut self) -> (StoreMut, &mut wasmer::Instance) {
127 (self.store.as_store_mut(), &mut self.instance)
128 }
129}
130
131impl<UserData> Instance for EntrypointInstance<UserData> {
132 type Runtime = Wasmer;
133 type UserData = UserData;
134 type UserDataReference<'a>
135 = MutexGuard<'a, UserData>
136 where
137 Self::UserData: 'a,
138 Self: 'a;
139 type UserDataMutReference<'a>
140 = MutexGuard<'a, UserData>
141 where
142 Self::UserData: 'a,
143 Self: 'a;
144
145 fn load_export(&mut self, name: &str) -> Option<Extern> {
146 self.instance_slot.load_export(name)
147 }
148
149 fn user_data(&self) -> Self::UserDataReference<'_> {
150 self.instance_slot.user_data()
151 }
152
153 fn user_data_mut(&mut self) -> Self::UserDataMutReference<'_> {
154 self.instance_slot.user_data()
155 }
156}
157
158pub type ReentrantInstance<'a, UserData> = FunctionEnvMut<'a, Environment<UserData>>;
161
162impl<UserData: 'static> Instance for ReentrantInstance<'_, UserData> {
163 type Runtime = Wasmer;
164 type UserData = UserData;
165 type UserDataReference<'a>
166 = MutexGuard<'a, UserData>
167 where
168 Self::UserData: 'a,
169 Self: 'a;
170 type UserDataMutReference<'a>
171 = MutexGuard<'a, UserData>
172 where
173 Self::UserData: 'a,
174 Self: 'a;
175
176 fn load_export(&mut self, name: &str) -> Option<Extern> {
177 self.data_mut().load_export(name)
178 }
179
180 fn user_data(&self) -> Self::UserDataReference<'_> {
181 FunctionEnvMut::data(self).user_data()
182 }
183
184 fn user_data_mut(&mut self) -> Self::UserDataMutReference<'_> {
185 FunctionEnvMut::data_mut(self).user_data()
186 }
187}
188
189pub struct Environment<UserData> {
191 exports: Arc<OnceLock<wasmer::Exports>>,
192 user_data: Arc<Mutex<UserData>>,
193}
194
195impl<UserData> Environment<UserData> {
196 fn new(user_data: UserData) -> Self {
198 Environment {
199 exports: Arc::new(OnceLock::new()),
200 user_data: Arc::new(Mutex::new(user_data)),
201 }
202 }
203
204 fn load_export(&mut self, name: &str) -> Option<Extern> {
210 self.exports
211 .get()
212 .expect("Attempted to get export before instance is loaded")
213 .get_extern(name)
214 .cloned()
215 }
216
217 fn user_data(&self) -> MutexGuard<'_, UserData> {
219 self.user_data
220 .try_lock()
221 .expect("Unexpected reentrant access to data")
222 }
223}
224
225impl<UserData> Clone for Environment<UserData> {
226 fn clone(&self) -> Self {
227 Environment {
228 exports: self.exports.clone(),
229 user_data: self.user_data.clone(),
230 }
231 }
232}