wasm/execution/
resumable.rs1use core::mem;
2
3use alloc::{
4 sync::{Arc, Weak},
5 vec::Vec,
6};
7
8use crate::{
9 core::slotmap::{SlotMap, SlotMapKey},
10 execution::interpreter_loop,
11 hooks::EmptyHookSet,
12 rw_spinlock::RwSpinLock,
13 value_stack::Stack,
14 RuntimeError, Value,
15};
16
17use super::RuntimeInstance;
18
19#[derive(Debug)]
20pub struct Resumable {
21 pub(crate) stack: Stack,
22 pub(crate) pc: usize,
23 pub(crate) stp: usize,
24 pub(crate) current_func_addr: usize,
25}
26
27#[derive(Default)]
28pub struct Dormitory(Arc<RwSpinLock<SlotMap<Resumable>>>);
29
30impl Dormitory {
31 #[allow(unused)]
32 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn insert(&self, resumable: Resumable) -> ResumableRef {
37 let key = self.0.write().insert(resumable);
38
39 ResumableRef {
40 dormitory: Arc::downgrade(&self.0),
41 key,
42 }
43 }
44}
45
46pub struct ResumableRef {
47 dormitory: Weak<RwSpinLock<SlotMap<Resumable>>>,
48 key: SlotMapKey<Resumable>,
49}
50
51impl ResumableRef {
52 pub fn resume<T>(
53 mut self,
54 runtime_instance: &mut RuntimeInstance<T>,
55 fuel: u32,
56 ) -> Result<RunState, RuntimeError> {
57 let Some(dormitory) = self.dormitory.upgrade() else {
59 return Err(RuntimeError::ResumableNotFound);
60 };
61
62 if !Arc::ptr_eq(&dormitory, &runtime_instance.store.dormitory.0) {
64 return Err(RuntimeError::ResumableNotFound);
65 }
66
67 let mut dormitory = dormitory.write();
69
70 let resumable = dormitory
73 .get_mut(&self.key)
74 .expect("the key to always be valid as self was not dropped yet");
75
76 let result = interpreter_loop::run(
78 resumable,
79 &mut runtime_instance.store,
80 EmptyHookSet,
81 Some(fuel),
82 );
83
84 match result {
85 Ok(()) => {
86 let resumable = dormitory.remove(&self.key)
87 .expect("that the resumable could not have been removed already, because then this self could not exist");
88
89 let _dormitory = mem::take(&mut self.dormitory);
92
93 Ok(RunState::Finished(resumable.stack.into_values()))
94 }
95 Err(RuntimeError::OutOfFuel) => Ok(RunState::Resumable(self)),
96 Err(err) => Err(err),
97 }
98 }
99}
100
101impl Drop for ResumableRef {
102 fn drop(&mut self) {
103 let Some(dormitory) = self.dormitory.upgrade() else {
104 return;
106 };
107
108 dormitory.write().remove(&self.key)
109 .expect("that the resumable could not have been removed already, because then this self could not exist or the dormitory weak pointer would have been None");
110 }
111}
112
113pub enum RunState {
114 Finished(Vec<Value>),
115 Resumable(ResumableRef),
116}
117
118#[cfg(test)]
119mod test {
120 use crate::value_stack::Stack;
121
122 use super::{Dormitory, Resumable};
123
124 #[test]
126 fn dormitory_constructor() {
127 let dorm = Dormitory::new();
128
129 let resumable = Resumable {
130 stack: Stack::new(),
131 pc: 11,
132 stp: 13,
133 current_func_addr: 17,
134 };
135
136 dorm.insert(resumable);
137 }
138}