Skip to main content

luau_vm/state/
thread.rs

1use core::ptr::{self, NonNull};
2
3use crate::Table;
4use crate::function::{Closure, RawUpVal, UpVal};
5use crate::gc::{GcObject, RawGcObject};
6use crate::handle::RawHandle;
7use crate::handle::sealed::Sealed;
8use crate::string::{RawTString, TString};
9use crate::table::RawLuaTable;
10use crate::thread::Thread;
11use crate::value::{RawTValue, TValueCursor};
12
13use super::{CallInfo, CallInfoCursor, RawCallInfo, RawGlobalState};
14
15#[repr(C)]
16pub struct RawLuaState {
17    pub tt: u8,
18    pub marked: u8,
19    pub memcat: u8,
20    pub status: u8,
21    pub active_memcat: u8,
22    pub is_active: bool,
23    pub single_step: bool,
24    pub top: *mut RawTValue,
25    pub base: *mut RawTValue,
26    pub global: *mut RawGlobalState,
27    pub ci: *mut RawCallInfo,
28    pub stack_last: *mut RawTValue,
29    pub stack: *mut RawTValue,
30    pub end_ci: *mut RawCallInfo,
31    pub base_ci: *mut RawCallInfo,
32    pub stack_size: i32,
33    pub size_ci: i32,
34    pub native_call_depth: u16,
35    pub base_native_call_depth: u16,
36    pub cached_slot: i32,
37    pub gt: *mut RawLuaTable,
38    pub open_upval: *mut RawUpVal,
39    pub gc_list: *mut RawGcObject,
40    pub name_call: *mut RawTString,
41    pub userdata: *mut (),
42}
43
44/// Unstable access to a thread's raw execution state.
45///
46/// # Safety
47///
48/// The thread and owning VM must be live. Returned handles, pointers, record
49/// views, and cursors are non-owning and are invalidated by their documented
50/// stack, call-frame, GC, close, reset, or destruction transitions.
51#[allow(
52    clippy::missing_safety_doc,
53    reason = "all methods share the capability-level safety contract"
54)]
55pub trait ThreadState: Sealed + RawHandle<Raw = RawLuaState> {
56    unsafe fn from_raw(raw: NonNull<RawLuaState>) -> Self
57    where
58        Self: Sized;
59
60    unsafe fn current_call_info_cursor(&self) -> CallInfoCursor;
61
62    unsafe fn base_call_info_cursor(&self) -> CallInfoCursor;
63
64    unsafe fn current_call_info(&self) -> CallInfo {
65        unsafe { self.current_call_info_cursor().call_info_unchecked() }
66    }
67
68    unsafe fn base_call_info(&self) -> CallInfo {
69        unsafe { self.base_call_info_cursor().call_info_unchecked() }
70    }
71
72    unsafe fn set_current_call_info(&self, call_info: CallInfoCursor);
73
74    unsafe fn stack(&self) -> TValueCursor;
75
76    unsafe fn stack_base(&self) -> TValueCursor;
77
78    unsafe fn stack_top(&self) -> TValueCursor;
79
80    unsafe fn stack_last(&self) -> TValueCursor;
81
82    unsafe fn set_stack(&self, stack: TValueCursor);
83
84    unsafe fn set_stack_base(&self, base: TValueCursor);
85
86    unsafe fn set_stack_top(&self, top: TValueCursor);
87
88    unsafe fn open_upvalue(&self) -> Option<UpVal>;
89
90    unsafe fn set_open_upvalue(&self, upvalue: Option<UpVal>);
91
92    unsafe fn gc_list(&self) -> Option<GcObject>;
93
94    unsafe fn set_gc_list(&self, gc_list: Option<GcObject>);
95
96    unsafe fn name_call(&self) -> Option<TString>;
97
98    unsafe fn set_name_call(&self, name_call: Option<TString>);
99
100    unsafe fn cached_slot(&self) -> i32;
101
102    unsafe fn set_cached_slot(&self, cached_slot: i32);
103
104    unsafe fn restore_call_frame(&self, call_info: CallInfoCursor, top: TValueCursor) {
105        unsafe {
106            self.set_current_call_info(call_info);
107            self.set_stack_base(call_info.call_info_unchecked().base());
108            self.set_stack_top(top);
109        }
110    }
111
112    unsafe fn globals(&self) -> Table;
113
114    unsafe fn set_globals(&self, globals: Table);
115
116    unsafe fn increment_native_call_depth(&self);
117
118    unsafe fn decrement_native_call_depth(&self);
119
120    unsafe fn increment_base_native_call_depth(&self);
121
122    unsafe fn decrement_base_native_call_depth(&self);
123
124    unsafe fn current_function(&self) -> Closure {
125        unsafe { self.current_call_info().function_closure() }
126    }
127
128    unsafe fn current_env(&self) -> Table {
129        unsafe {
130            if self.current_call_info() == self.base_call_info() {
131                self.globals()
132            } else {
133                self.current_function().env()
134            }
135        }
136    }
137}
138
139impl ThreadState for Thread {
140    unsafe fn from_raw(raw: NonNull<RawLuaState>) -> Self {
141        Self { raw }
142    }
143
144    unsafe fn current_call_info_cursor(&self) -> CallInfoCursor {
145        unsafe { CallInfoCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().ci) }
146    }
147
148    unsafe fn base_call_info_cursor(&self) -> CallInfoCursor {
149        unsafe { CallInfoCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().base_ci) }
150    }
151
152    unsafe fn set_current_call_info(&self, call_info: CallInfoCursor) {
153        unsafe {
154            self.as_ptr().as_mut().unwrap_unchecked().ci = call_info.as_ptr();
155        }
156    }
157
158    unsafe fn stack(&self) -> TValueCursor {
159        unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().stack) }
160    }
161
162    unsafe fn stack_base(&self) -> TValueCursor {
163        unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().base) }
164    }
165
166    unsafe fn stack_top(&self) -> TValueCursor {
167        unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().top) }
168    }
169
170    unsafe fn stack_last(&self) -> TValueCursor {
171        unsafe { TValueCursor::from_ptr(self.as_ptr().as_ref().unwrap_unchecked().stack_last) }
172    }
173
174    unsafe fn set_stack(&self, stack: TValueCursor) {
175        unsafe {
176            self.as_ptr().as_mut().unwrap_unchecked().stack = stack.as_ptr();
177        }
178    }
179
180    unsafe fn set_stack_base(&self, base: TValueCursor) {
181        unsafe {
182            self.as_ptr().as_mut().unwrap_unchecked().base = base.as_ptr();
183        }
184    }
185
186    unsafe fn set_stack_top(&self, top: TValueCursor) {
187        unsafe {
188            self.as_ptr().as_mut().unwrap_unchecked().top = top.as_ptr();
189        }
190    }
191
192    unsafe fn open_upvalue(&self) -> Option<UpVal> {
193        unsafe {
194            NonNull::new(self.as_ptr().as_ref().unwrap_unchecked().open_upval)
195                .map(|upvalue| UpVal::from_raw(upvalue))
196        }
197    }
198
199    unsafe fn set_open_upvalue(&self, upvalue: Option<UpVal>) {
200        unsafe {
201            self.as_ptr().as_mut().unwrap_unchecked().open_upval =
202                upvalue.map_or(ptr::null_mut(), |upvalue| upvalue.as_ptr());
203        }
204    }
205
206    unsafe fn gc_list(&self) -> Option<GcObject> {
207        unsafe {
208            NonNull::new(self.as_ptr().as_ref().unwrap_unchecked().gc_list)
209                .map(|raw| GcObject::from_raw(raw))
210        }
211    }
212
213    unsafe fn set_gc_list(&self, gc_list: Option<GcObject>) {
214        unsafe {
215            self.as_ptr().as_mut().unwrap_unchecked().gc_list =
216                gc_list.map_or(ptr::null_mut(), |object| object.as_ptr());
217        }
218    }
219
220    unsafe fn name_call(&self) -> Option<TString> {
221        unsafe {
222            NonNull::new(self.as_ptr().as_ref().unwrap_unchecked().name_call)
223                .map(|raw| TString::from_raw(raw))
224        }
225    }
226
227    unsafe fn set_name_call(&self, name_call: Option<TString>) {
228        unsafe {
229            self.as_ptr().as_mut().unwrap_unchecked().name_call =
230                name_call.map_or(ptr::null_mut(), |name_call| name_call.as_ptr());
231        }
232    }
233
234    unsafe fn cached_slot(&self) -> i32 {
235        unsafe { self.as_ptr().as_ref().unwrap_unchecked().cached_slot }
236    }
237
238    unsafe fn set_cached_slot(&self, cached_slot: i32) {
239        unsafe {
240            self.as_ptr().as_mut().unwrap_unchecked().cached_slot = cached_slot;
241        }
242    }
243
244    unsafe fn globals(&self) -> Table {
245        unsafe {
246            debug_assert!(!self.as_ptr().as_ref().unwrap_unchecked().gt.is_null());
247            Table::from_raw(NonNull::new_unchecked(
248                self.as_ptr().as_ref().unwrap_unchecked().gt,
249            ))
250        }
251    }
252
253    unsafe fn set_globals(&self, globals: Table) {
254        unsafe {
255            self.as_ptr().as_mut().unwrap_unchecked().gt = globals.as_ptr();
256        }
257    }
258
259    unsafe fn increment_native_call_depth(&self) {
260        unsafe {
261            self.as_ptr().as_mut().unwrap_unchecked().native_call_depth += 1;
262        }
263    }
264
265    unsafe fn decrement_native_call_depth(&self) {
266        unsafe {
267            self.as_ptr().as_mut().unwrap_unchecked().native_call_depth -= 1;
268        }
269    }
270
271    unsafe fn increment_base_native_call_depth(&self) {
272        unsafe {
273            self.as_ptr()
274                .as_mut()
275                .unwrap_unchecked()
276                .base_native_call_depth += 1;
277        }
278    }
279
280    unsafe fn decrement_base_native_call_depth(&self) {
281        unsafe {
282            self.as_ptr()
283                .as_mut()
284                .unwrap_unchecked()
285                .base_native_call_depth -= 1;
286        }
287    }
288}