1mod coroutine;
2mod protected;
3mod stack;
4
5pub(crate) use coroutine::{resume as resume_protected, resume_handle};
6pub use protected::{ErrorRuntime, LuaProtectedErrorFrame, Pfunc, ProtectedCall};
7pub use stack::ThreadStack;
8
9use crate::gc::{GcBarrier, GcRuntime};
10use crate::handle::RawHandle;
11use crate::handle::sealed::Sealed;
12use crate::state::ThreadState;
13use crate::state::{THREAD_STATUS_BREAK, THREAD_STATUS_SCHEDULED_REENTRY, THREAD_STATUS_YIELD};
14use crate::thread::{LUA_MULTRET, Thread};
15use crate::value::TValueCursor;
16use crate::vm::{PreCallResult, VmCallFrame, VmExecution};
17use crate::{VmControl, VmExit, VmResult};
18
19#[allow(
27 clippy::missing_safety_doc,
28 reason = "all methods share the capability-level safety contract"
29)]
30pub trait CallRuntime: Sealed {
31 unsafe fn perform_cally(&self, function: TValueCursor, n_results: i32) -> VmResult;
32 unsafe fn call_int(
33 &self,
34 function: TValueCursor,
35 n_results: i32,
36 prepare_reentry: bool,
37 ) -> VmResult;
38 unsafe fn call_internal(&self, function: TValueCursor, n_results: i32) -> VmResult;
39 unsafe fn call_no_yield(&self, function: TValueCursor, n_results: i32) -> VmResult;
40}
41
42unsafe fn perform_call(
44 thread: &Thread,
45 function: TValueCursor,
46 n_results: i32,
47 prepare_reentry: bool,
48) -> VmResult {
49 if unsafe { thread.pre_call(function, n_results)? } == PreCallResult::Lua {
50 unsafe {
51 let call_info = thread.current_call_info();
52 call_info.as_ptr().as_mut().unwrap_unchecked().flags |=
53 crate::state::LUA_CALLINFO_RETURN;
54
55 let old_active = thread.as_ptr().as_ref().unwrap_unchecked().is_active;
56 thread.as_ptr().as_mut().unwrap_unchecked().is_active = true;
57 thread.thread_barrier();
58
59 if prepare_reentry {
60 thread.as_ptr().as_mut().unwrap_unchecked().status =
61 THREAD_STATUS_SCHEDULED_REENTRY;
62 if !old_active {
63 thread.as_ptr().as_mut().unwrap_unchecked().is_active = false;
64 }
65 Err(VmExit::Control(VmControl::Yield))
66 } else {
67 let result = thread.execute();
68 if !old_active {
69 thread.as_ptr().as_mut().unwrap_unchecked().is_active = false;
70 }
71 result
72 }
73 }
74 } else {
75 Ok(())
76 }
77}
78
79impl CallRuntime for Thread {
80 unsafe fn perform_cally(&self, function: TValueCursor, n_results: i32) -> VmResult {
82 unsafe {
83 self.increment_native_call_depth();
84 if self.as_ptr().as_ref().unwrap_unchecked().native_call_depth
85 >= crate::thread::LUAI_MAX_NATIVE_CALLS
86 {
87 self.check_c_stack()?;
88 }
89 self.increment_base_native_call_depth();
90 let ci_offset = self.save_ci(self.current_call_info_cursor());
91
92 match perform_call(self, function, n_results, false) {
93 Ok(()) => {}
94 Err(VmExit::Control(control)) => {
95 let caller = self.restore_ci(ci_offset).call_info_unchecked();
96
97 caller.as_ptr().as_mut().unwrap_unchecked().flags |=
98 crate::state::LUA_CALLINFO_OP_YIELD;
99
100 return Err(VmExit::Control(control));
101 }
102 Err(exit) => return Err(exit),
103 }
104
105 self.decrement_base_native_call_depth();
106 self.decrement_native_call_depth();
107 self.check_gc()?;
108 Ok(())
109 }
110 }
111
112 unsafe fn call_int(
114 &self,
115 function: TValueCursor,
116 n_results: i32,
117 prepare_reentry: bool,
118 ) -> VmResult {
119 let (from_yieldable_native_call, function_offset, ci_offset) = unsafe {
120 self.increment_native_call_depth();
121 if self.as_ptr().as_ref().unwrap_unchecked().native_call_depth
122 >= crate::thread::LUAI_MAX_NATIVE_CALLS
123 {
124 self.check_c_stack()?;
125 }
126
127 let mut from_yieldable_native_call = false;
128 if self.current_call_info() != self.base_call_info() {
129 let current = self.current_call_info().function_closure();
130 if current.is_native() && current.native_data().continuation.is_some() {
131 from_yieldable_native_call = true;
132 self.increment_base_native_call_depth();
133 }
134 }
135
136 let function_offset = self.save_stack(function);
137 let ci_offset = self.save_ci(self.current_call_info_cursor());
138 (from_yieldable_native_call, function_offset, ci_offset)
139 };
140
141 unsafe {
142 let result = perform_call(self, function, n_results, prepare_reentry);
143 let control = match result {
144 Ok(()) => None,
145 Err(VmExit::Control(control)) => Some(control),
146 Err(exit) => return Err(exit),
147 };
148 let suspended = control.is_some();
149
150 if from_yieldable_native_call {
151 self.decrement_base_native_call_depth();
152
153 if suspended {
154 let caller = self.restore_ci(ci_offset).call_info_unchecked();
155 let caller_top =
156 self.restore_stack(function_offset)
157 .add(if n_results != LUA_MULTRET {
158 n_results as usize
159 } else {
160 0
161 });
162
163 caller.set_top(caller_top);
164 }
165 }
166
167 if n_results != LUA_MULTRET && !suspended {
168 self.set_stack_top(self.restore_stack(function_offset).add(n_results as usize))
169 }
170
171 self.decrement_native_call_depth();
172 self.check_gc()?;
173
174 if let Some(control) = control {
175 return Err(VmExit::Control(control));
176 }
177 }
178 Ok(())
179 }
180
181 unsafe fn call_internal(&self, function: TValueCursor, n_results: i32) -> VmResult {
183 unsafe { self.call_int(function, n_results, false) }
184 }
185
186 unsafe fn call_no_yield(&self, function: TValueCursor, n_results: i32) -> VmResult {
188 unsafe {
189 self.increment_native_call_depth();
190 if self.as_ptr().as_ref().unwrap_unchecked().native_call_depth
191 >= crate::thread::LUAI_MAX_NATIVE_CALLS
192 {
193 self.check_c_stack()?;
194 }
195 debug_assert!(
196 self.as_ptr().as_ref().unwrap_unchecked().native_call_depth
197 > self
198 .as_ptr()
199 .as_ref()
200 .unwrap_unchecked()
201 .base_native_call_depth
202 );
203 let function_offset = self.save_stack(function);
204 perform_call(self, function, n_results, false)?;
205
206 debug_assert!(!matches!(
207 self.as_ptr().as_ref().unwrap_unchecked().status,
208 THREAD_STATUS_YIELD | THREAD_STATUS_BREAK | THREAD_STATUS_SCHEDULED_REENTRY
209 ));
210 if n_results != LUA_MULTRET {
211 self.set_stack_top(self.restore_stack(function_offset).add(n_results as usize))
212 }
213
214 self.decrement_native_call_depth();
215 self.check_gc()?;
216 }
217 Ok(())
218 }
219}