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, FunctionEnvMut, Global, Instance, Memory, MemoryView, Module,
12 Table, TypedFunction, Value,
13};
14use wasmer_wasix_types::wasi::Errno;
15
16use crate::{WasiEnv, state::LinkError};
17
18use super::Linker;
19
20#[derive(Debug, Clone)]
25pub struct WasiModuleInstanceHandles {
26 pub(crate) memory: Memory,
30 pub(crate) instance: wasmer::Instance,
31
32 pub(crate) indirect_function_table: Option<Table>,
34
35 pub(crate) stack_pointer: Option<Global>,
37
38 pub(crate) data_end: Option<Global>,
40
41 pub(crate) stack_low: Option<Global>,
43
44 pub(crate) stack_high: Option<Global>,
46
47 pub(crate) tls_base: Option<Global>,
49
50 pub(crate) start: Option<TypedFunction<(), ()>>,
52
53 #[allow(dead_code)]
56 pub(crate) initialize: Option<TypedFunction<(), ()>>,
57
58 pub(crate) thread_spawn: Option<TypedFunction<(i32, i32), ()>>,
62
63 pub(crate) signal: Option<TypedFunction<i32, ()>>,
67
68 pub(crate) signal_set: bool,
72
73 pub(crate) has_stack_checkpoint: bool,
76
77 #[allow(dead_code)]
82 pub(crate) asyncify_start_unwind: Option<TypedFunction<i32, ()>>,
83
84 #[allow(dead_code)]
93 pub(crate) asyncify_stop_unwind: Option<TypedFunction<(), ()>>,
94
95 #[allow(dead_code)]
101 pub(crate) asyncify_start_rewind: Option<TypedFunction<i32, ()>>,
102
103 #[allow(dead_code)]
107 pub(crate) asyncify_stop_rewind: Option<TypedFunction<(), ()>>,
108
109 #[allow(dead_code)]
115 pub(crate) asyncify_get_state: Option<TypedFunction<(), i32>>,
116}
117
118impl WasiModuleInstanceHandles {
119 pub fn new(
120 memory: Memory,
121 store: &impl AsStoreRef,
122 instance: Instance,
123 indirect_function_table: Option<Table>,
124 ) -> Self {
125 let has_stack_checkpoint = instance
126 .module()
127 .imports()
128 .any(|f| f.name() == "stack_checkpoint");
129 Self {
130 memory,
131 indirect_function_table: indirect_function_table.or_else(|| {
132 instance
133 .exports
134 .get_table("__indirect_function_table")
135 .cloned()
136 .ok()
137 }),
138 stack_pointer: instance.exports.get_global("__stack_pointer").cloned().ok(),
139 data_end: instance.exports.get_global("__data_end").cloned().ok(),
140 stack_low: instance.exports.get_global("__stack_low").cloned().ok(),
141 stack_high: instance.exports.get_global("__stack_high").cloned().ok(),
142 tls_base: instance.exports.get_global("__tls_base").cloned().ok(),
143 start: instance.exports.get_typed_function(store, "_start").ok(),
144 initialize: instance
145 .exports
146 .get_typed_function(store, "_initialize")
147 .ok(),
148 thread_spawn: instance
149 .exports
150 .get_typed_function(store, "wasi_thread_start")
151 .ok(),
152 signal: instance
153 .exports
154 .get_typed_function(&store, "__wasm_signal")
155 .ok(),
156 has_stack_checkpoint,
157 signal_set: false,
158 asyncify_start_unwind: instance
159 .exports
160 .get_typed_function(store, "asyncify_start_unwind")
161 .ok(),
162 asyncify_stop_unwind: instance
163 .exports
164 .get_typed_function(store, "asyncify_stop_unwind")
165 .ok(),
166 asyncify_start_rewind: instance
167 .exports
168 .get_typed_function(store, "asyncify_start_rewind")
169 .ok(),
170 asyncify_stop_rewind: instance
171 .exports
172 .get_typed_function(store, "asyncify_stop_rewind")
173 .ok(),
174 asyncify_get_state: instance
175 .exports
176 .get_typed_function(store, "asyncify_get_state")
177 .ok(),
178 instance,
179 }
180 }
181
182 pub fn module(&self) -> &Module {
183 self.instance.module()
184 }
185
186 pub fn module_clone(&self) -> Module {
187 self.instance.module().clone()
188 }
189
190 pub fn memory_view<'a>(&'a self, store: &'a (impl AsStoreRef + ?Sized)) -> MemoryView<'a> {
193 self.memory.view(store)
194 }
195
196 pub fn memory(&self) -> &Memory {
199 &self.memory
200 }
201
202 pub fn memory_clone(&self) -> Memory {
205 self.memory.clone()
206 }
207
208 pub fn instance(&self) -> &Instance {
209 &self.instance
210 }
211}
212
213#[derive(Debug, Clone)]
214pub enum WasiModuleTreeHandles {
215 Static(WasiModuleInstanceHandles),
216 Dynamic {
217 linker: Linker,
218 main_module_instance_handles: WasiModuleInstanceHandles,
219 },
220}
221
222#[derive(thiserror::Error, Debug, Clone)]
223pub enum FunctionLookupError {
224 #[error("No function found at the requested index `{0}`")]
225 Empty(u32),
227 #[error("Table index `{0}` out of bounds")]
228 OutOfBounds(u32),
230 #[error("The table does not contain functions")]
231 NotAFunctionTable,
233 #[error("No indirect function table available")]
234 NoIndirectFunctionTable,
236}
237impl From<FunctionLookupError> for Errno {
238 fn from(e: FunctionLookupError) -> Self {
239 match e {
240 FunctionLookupError::Empty(_) => Errno::Inval,
241 FunctionLookupError::OutOfBounds(_) => Errno::Inval,
242 FunctionLookupError::NotAFunctionTable => Errno::Inval,
243 FunctionLookupError::NoIndirectFunctionTable => Errno::Notsup,
244 }
245 }
246}
247
248impl WasiModuleTreeHandles {
249 pub(crate) fn main_module_instance_handles(&self) -> &WasiModuleInstanceHandles {
253 match self {
254 WasiModuleTreeHandles::Static(handles) => handles,
255 WasiModuleTreeHandles::Dynamic {
256 main_module_instance_handles,
257 ..
258 } => main_module_instance_handles,
259 }
260 }
261
262 pub(crate) fn main_module_instance_handles_mut(&mut self) -> &mut WasiModuleInstanceHandles {
264 match self {
265 WasiModuleTreeHandles::Static(handles) => handles,
266 WasiModuleTreeHandles::Dynamic {
267 main_module_instance_handles,
268 ..
269 } => main_module_instance_handles,
270 }
271 }
272
273 pub(crate) fn static_module_instance_handles(&self) -> Option<&WasiModuleInstanceHandles> {
276 match self {
277 WasiModuleTreeHandles::Static(handles) => Some(handles),
278 WasiModuleTreeHandles::Dynamic { .. } => None,
279 }
280 }
281
282 #[allow(dead_code)]
284 pub(crate) fn static_module_instance_handles_mut(
285 &mut self,
286 ) -> Option<&mut WasiModuleInstanceHandles> {
287 match self {
288 WasiModuleTreeHandles::Static(handles) => Some(handles),
289 WasiModuleTreeHandles::Dynamic { .. } => None,
290 }
291 }
292
293 pub(crate) fn ensure_static_module(&self) -> Result<(), ()> {
297 match self {
298 WasiModuleTreeHandles::Static(_) => Ok(()),
299 _ => Err(()),
300 }
301 }
302
303 pub fn memory_view<'a>(&'a self, store: &'a (impl AsStoreRef + ?Sized)) -> MemoryView<'a> {
306 self.main_module_instance_handles().memory.view(store)
307 }
308
309 pub fn memory(&self) -> &Memory {
312 &self.main_module_instance_handles().memory
313 }
314
315 pub fn memory_clone(&self) -> Memory {
318 self.main_module_instance_handles().memory.clone()
319 }
320
321 pub fn linker(&self) -> Option<&Linker> {
322 match self {
323 Self::Static(_) => None,
324 Self::Dynamic { linker, .. } => Some(linker),
325 }
326 }
327
328 pub fn indirect_function_table_lookup(
335 &self,
336 store: &mut impl AsStoreMut,
337 index: u32,
338 ) -> Result<Function, FunctionLookupError> {
339 let value = self
340 .main_module_instance_handles()
341 .indirect_function_table
342 .as_ref()
343 .ok_or(FunctionLookupError::NoIndirectFunctionTable)?
344 .get(store, index);
345 let Some(value) = value else {
346 trace!(
347 function_id = index,
348 "Function not found in indirect function table"
349 );
350 return Err(FunctionLookupError::OutOfBounds(index));
351 };
352 let Value::FuncRef(funcref) = value else {
353 error!("Function table contains something other than a funcref");
354 return Err(FunctionLookupError::NotAFunctionTable);
355 };
356 let Some(funcref) = funcref else {
357 trace!(function_id = index, "No function at the supplied index");
358 return Err(FunctionLookupError::Empty(index));
359 };
360 Ok(funcref)
361 }
362
363 pub fn is_closure(
367 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
368 function_id: u32,
369 ) -> Result<bool, LinkError> {
370 #[allow(clippy::borrow_deref_ref)]
374 match &*ctx.data().inner() {
375 WasiModuleTreeHandles::Static(_) => Ok(false),
376 WasiModuleTreeHandles::Dynamic { linker, .. } => {
377 linker.clone().is_closure(function_id, ctx)
378 }
379 }
380 }
381}