wasmer_wasix/state/handles/
mod.rs1mod global;
2mod thread_local;
3
4#[cfg(any(feature = "sys", feature = "sys-minimal"))]
5pub(crate) use global::*;
6#[cfg(feature = "js")]
7pub(crate) use thread_local::*;
8
9use tracing::{error, trace};
10use wasmer::{
11 AsStoreMut, AsStoreRef, Function, Global, Instance, Memory, MemoryView, Module, Table,
12 TypedFunction, Value,
13};
14use wasmer_wasix_types::wasi::Errno;
15
16use super::Linker;
17
18#[derive(Debug, Clone)]
23pub struct WasiModuleInstanceHandles {
24 pub(crate) memory: Memory,
28 pub(crate) instance: wasmer::Instance,
29
30 pub(crate) indirect_function_table: Option<Table>,
32
33 pub(crate) stack_pointer: Option<Global>,
35
36 pub(crate) data_end: Option<Global>,
38
39 pub(crate) stack_low: Option<Global>,
41
42 pub(crate) stack_high: Option<Global>,
44
45 pub(crate) tls_base: Option<Global>,
47
48 pub(crate) start: Option<TypedFunction<(), ()>>,
50
51 #[allow(dead_code)]
54 pub(crate) initialize: Option<TypedFunction<(), ()>>,
55
56 pub(crate) thread_spawn: Option<TypedFunction<(i32, i32), ()>>,
60
61 pub(crate) signal: Option<TypedFunction<i32, ()>>,
65
66 pub(crate) signal_set: bool,
70
71 pub(crate) has_stack_checkpoint: bool,
74
75 #[allow(dead_code)]
80 pub(crate) asyncify_start_unwind: Option<TypedFunction<i32, ()>>,
81
82 #[allow(dead_code)]
91 pub(crate) asyncify_stop_unwind: Option<TypedFunction<(), ()>>,
92
93 #[allow(dead_code)]
99 pub(crate) asyncify_start_rewind: Option<TypedFunction<i32, ()>>,
100
101 #[allow(dead_code)]
105 pub(crate) asyncify_stop_rewind: Option<TypedFunction<(), ()>>,
106
107 #[allow(dead_code)]
113 pub(crate) asyncify_get_state: Option<TypedFunction<(), i32>>,
114}
115
116impl WasiModuleInstanceHandles {
117 pub fn new(
118 memory: Memory,
119 store: &impl AsStoreRef,
120 instance: Instance,
121 indirect_function_table: Option<Table>,
122 ) -> Self {
123 let has_stack_checkpoint = instance
124 .module()
125 .imports()
126 .any(|f| f.name() == "stack_checkpoint");
127 Self {
128 memory,
129 indirect_function_table: indirect_function_table.or_else(|| {
130 instance
131 .exports
132 .get_table("__indirect_function_table")
133 .cloned()
134 .ok()
135 }),
136 stack_pointer: instance.exports.get_global("__stack_pointer").cloned().ok(),
137 data_end: instance.exports.get_global("__data_end").cloned().ok(),
138 stack_low: instance.exports.get_global("__stack_low").cloned().ok(),
139 stack_high: instance.exports.get_global("__stack_high").cloned().ok(),
140 tls_base: instance.exports.get_global("__tls_base").cloned().ok(),
141 start: instance.exports.get_typed_function(store, "_start").ok(),
142 initialize: instance
143 .exports
144 .get_typed_function(store, "_initialize")
145 .ok(),
146 thread_spawn: instance
147 .exports
148 .get_typed_function(store, "wasi_thread_start")
149 .ok(),
150 signal: instance
151 .exports
152 .get_typed_function(&store, "__wasm_signal")
153 .ok(),
154 has_stack_checkpoint,
155 signal_set: false,
156 asyncify_start_unwind: instance
157 .exports
158 .get_typed_function(store, "asyncify_start_unwind")
159 .ok(),
160 asyncify_stop_unwind: instance
161 .exports
162 .get_typed_function(store, "asyncify_stop_unwind")
163 .ok(),
164 asyncify_start_rewind: instance
165 .exports
166 .get_typed_function(store, "asyncify_start_rewind")
167 .ok(),
168 asyncify_stop_rewind: instance
169 .exports
170 .get_typed_function(store, "asyncify_stop_rewind")
171 .ok(),
172 asyncify_get_state: instance
173 .exports
174 .get_typed_function(store, "asyncify_get_state")
175 .ok(),
176 instance,
177 }
178 }
179
180 pub fn module(&self) -> &Module {
181 self.instance.module()
182 }
183
184 pub fn module_clone(&self) -> Module {
185 self.instance.module().clone()
186 }
187
188 pub fn memory_view<'a>(&'a self, store: &'a (impl AsStoreRef + ?Sized)) -> MemoryView<'a> {
191 self.memory.view(store)
192 }
193
194 pub fn memory(&self) -> &Memory {
197 &self.memory
198 }
199
200 pub fn memory_clone(&self) -> Memory {
203 self.memory.clone()
204 }
205
206 pub fn instance(&self) -> &Instance {
207 &self.instance
208 }
209}
210
211#[derive(Debug, Clone)]
212pub enum WasiModuleTreeHandles {
213 Static(WasiModuleInstanceHandles),
214 Dynamic {
215 linker: Linker,
216 main_module_instance_handles: WasiModuleInstanceHandles,
217 },
218}
219
220#[derive(thiserror::Error, Debug, Clone)]
221pub enum FunctionLookupError {
222 #[error("No function found at the requested index `{0}`")]
223 Empty(u32),
225 #[error("Table index `{0}` out of bounds")]
226 OutOfBounds(u32),
228 #[error("The table does not contain functions")]
229 NotAFunctionTable,
231 #[error("No indirect function table available")]
232 NoIndirectFunctionTable,
234}
235impl From<FunctionLookupError> for Errno {
236 fn from(e: FunctionLookupError) -> Self {
237 match e {
238 FunctionLookupError::Empty(_) => Errno::Inval,
239 FunctionLookupError::OutOfBounds(_) => Errno::Inval,
240 FunctionLookupError::NotAFunctionTable => Errno::Inval,
241 FunctionLookupError::NoIndirectFunctionTable => Errno::Notsup,
242 }
243 }
244}
245
246impl WasiModuleTreeHandles {
247 pub(crate) fn main_module_instance_handles(&self) -> &WasiModuleInstanceHandles {
251 match self {
252 WasiModuleTreeHandles::Static(handles) => handles,
253 WasiModuleTreeHandles::Dynamic {
254 main_module_instance_handles,
255 ..
256 } => main_module_instance_handles,
257 }
258 }
259
260 pub(crate) fn main_module_instance_handles_mut(&mut self) -> &mut WasiModuleInstanceHandles {
262 match self {
263 WasiModuleTreeHandles::Static(handles) => handles,
264 WasiModuleTreeHandles::Dynamic {
265 main_module_instance_handles,
266 ..
267 } => main_module_instance_handles,
268 }
269 }
270
271 pub(crate) fn static_module_instance_handles(&self) -> Option<&WasiModuleInstanceHandles> {
274 match self {
275 WasiModuleTreeHandles::Static(handles) => Some(handles),
276 WasiModuleTreeHandles::Dynamic { .. } => None,
277 }
278 }
279
280 #[allow(dead_code)]
282 pub(crate) fn static_module_instance_handles_mut(
283 &mut self,
284 ) -> Option<&mut WasiModuleInstanceHandles> {
285 match self {
286 WasiModuleTreeHandles::Static(handles) => Some(handles),
287 WasiModuleTreeHandles::Dynamic { .. } => None,
288 }
289 }
290
291 pub(crate) fn ensure_static_module(&self) -> Result<(), ()> {
295 match self {
296 WasiModuleTreeHandles::Static(_) => Ok(()),
297 _ => Err(()),
298 }
299 }
300
301 pub fn memory_view<'a>(&'a self, store: &'a (impl AsStoreRef + ?Sized)) -> MemoryView<'a> {
304 self.main_module_instance_handles().memory.view(store)
305 }
306
307 pub fn memory(&self) -> &Memory {
310 &self.main_module_instance_handles().memory
311 }
312
313 pub fn memory_clone(&self) -> Memory {
316 self.main_module_instance_handles().memory.clone()
317 }
318
319 pub fn linker(&self) -> Option<&Linker> {
320 match self {
321 Self::Static(_) => None,
322 Self::Dynamic { linker, .. } => Some(linker),
323 }
324 }
325
326 pub fn indirect_function_table_lookup(
333 &self,
334 store: &mut impl AsStoreMut,
335 index: u32,
336 ) -> Result<Function, FunctionLookupError> {
337 let value = self
338 .main_module_instance_handles()
339 .indirect_function_table
340 .as_ref()
341 .ok_or(FunctionLookupError::NoIndirectFunctionTable)?
342 .get(store, index);
343 let Some(value) = value else {
344 trace!(
345 function_id = index,
346 "Function not found in indirect function table"
347 );
348 return Err(FunctionLookupError::OutOfBounds(index));
349 };
350 let Value::FuncRef(funcref) = value else {
351 error!("Function table contains something other than a funcref");
352 return Err(FunctionLookupError::NotAFunctionTable);
353 };
354 let Some(funcref) = funcref else {
355 trace!(function_id = index, "No function at the supplied index");
356 return Err(FunctionLookupError::Empty(index));
357 };
358 Ok(funcref)
359 }
360
361 pub fn is_closure(&self, function_id: u32) -> bool {
365 match self {
366 WasiModuleTreeHandles::Static(_) => false,
367 WasiModuleTreeHandles::Dynamic { linker, .. } => linker.is_closure(function_id),
368 }
369 }
370}