Skip to main content

luau_vm/state/
mod.rs

1mod call_info;
2mod callbacks;
3mod lifecycle;
4mod thread;
5
6pub(crate) use crate::memory::allocator::VmAllocator;
7pub use crate::memory::allocator::{LuaAllocator, SystemLuaAllocator, VM_ALLOC_ALIGN};
8pub use call_info::{CallInfo, CallInfoCursor, RawCallInfo, RawCallInfoSaved};
9pub use callbacks::{
10    AllocateCallback, EmbedderGc, EmbedderMark, ExecutionCallbackStorage, ExecutionClose,
11    ExecutionCounterData, ExecutionDestroy, ExecutionDisable, ExecutionEnter,
12    ExecutionInlineFunction, ExecutionInterrupt, ExecutionMemorySize, ExecutionTypeMapping,
13    GcInterrupt, GcInterruptCallback, GcPhase, InterruptKind, InterruptRequest, LuaCallbacks,
14    LuaExecutionCallbacks, PatternInterrupt, ProtectedErrorAction, ProtectedErrorCallback,
15    UserAtomCallback, UserThreadCallback,
16};
17pub use lifecycle::ThreadLifecycle;
18pub(crate) use lifecycle::open_main_state;
19pub use thread::{RawLuaState, ThreadState};
20
21use core::cell::UnsafeCell;
22use core::ptr::NonNull;
23
24use crate::call::LuaProtectedErrorFrame;
25use crate::function::RawUpVal;
26use crate::gc::{GcStats, RawGcObject};
27use crate::handle::RawHandle;
28use crate::handle::sealed::Sealed;
29use crate::memory::{LUA_MEMORY_CATEGORIES, LUA_SIZE_CLASSES, RawLuaPage};
30use crate::metamethod::TM_N;
31use crate::string::{RawTString, StringTable};
32use crate::table::RawLuaTable;
33use crate::thread::{LUA_MIN_STACK, LUAI_MAX_NATIVE_CALLS, Thread};
34use crate::types::LUA_T_COUNT;
35use crate::userdata::{LuaUserdataDirectAccessData, UserdataTypeRegistry};
36use crate::value::{RawTValue, TValue};
37
38#[repr(C)]
39pub struct RawMainState {
40    pub state: RawLuaState,
41    pub global: RawGlobalState,
42}
43
44#[repr(C)]
45pub struct RawGlobalState {
46    pub string_table: StringTable,
47    pub(crate) allocator: NonNull<VmAllocator>,
48    pub current_white: u8,
49    pub gc_state: u8,
50    pub gray: *mut RawGcObject,
51    pub gray_again: *mut RawGcObject,
52    pub weak: *mut RawGcObject,
53    pub gc_threshold: usize,
54    pub total_bytes: usize,
55    pub gc_goal: i32,
56    pub gc_step_mul: i32,
57    pub gc_step_size: i32,
58    pub free_pages: [*mut RawLuaPage; LUA_SIZE_CLASSES],
59    pub free_gco_pages: [*mut RawLuaPage; LUA_SIZE_CLASSES],
60    pub all_pages: *mut RawLuaPage,
61    pub all_gco_pages: *mut RawLuaPage,
62    pub sweep_gco_page: *mut RawLuaPage,
63    pub main_thread: *mut RawLuaState,
64    pub uv_head: RawUpVal,
65    pub mt: [*mut RawLuaTable; LUA_T_COUNT],
66    pub tt_name: [*mut RawTString; LUA_T_COUNT],
67    pub tm_name: [*mut RawTString; TM_N],
68    pub pseudo_temp: RawTValue,
69    pub registry: RawTValue,
70    pub registry_free: i32,
71    pub protected_error: *mut LuaProtectedErrorFrame,
72    pub rng_state: u64,
73    pub ptr_enc_key: [u64; 4],
74    pub cb: LuaCallbacks,
75    pub ecb: LuaExecutionCallbacks,
76    pub ecb_data: ExecutionCallbackStorage,
77    pub(crate) userdata_type_registry: UnsafeCell<UserdataTypeRegistry>,
78    pub userdata_direct: [LuaUserdataDirectAccessData; crate::userdata::USERDATA_INTERNAL_LIMIT],
79    pub memcat_bytes: [usize; LUA_MEMORY_CATEGORIES],
80    pub userdata_gc: [Option<crate::userdata::LuaDestructor>; crate::userdata::USERDATA_TAG_LIMIT],
81    pub userdata_mark:
82        [Option<crate::userdata::LuaUserdataMark>; crate::userdata::USERDATA_TAG_LIMIT],
83    pub userdata_mt: [*mut RawLuaTable; crate::userdata::USERDATA_TAG_LIMIT],
84    pub weak_registry: RawTValue,
85    pub weak_registry_free: i32,
86    pub embedder_gc: Option<EmbedderGc>,
87    pub light_userdata_name: [*mut RawTString; crate::userdata::LIGHT_USERDATA_TAG_LIMIT],
88    pub userdata_direct_fields: [*mut RawLuaTable; crate::userdata::USERDATA_INTERNAL_LIMIT],
89    pub gc_stats: GcStats,
90    pub last_proto_id: u32,
91}
92
93#[derive(Clone, Copy, PartialEq, Eq)]
94#[repr(transparent)]
95/// Non-owning identity of a VM's global state record.
96///
97/// # Safety model for unsafe methods
98///
99/// The owning VM must remain live. Returned threads, objects, pointers, and
100/// record views are non-owning and must not outlive their storage. Mutation
101/// must be serialized with VM execution and preserve the owning subsystem's
102/// invariants.
103pub struct GlobalState {
104    raw: NonNull<RawGlobalState>,
105}
106
107#[allow(
108    clippy::missing_safety_doc,
109    reason = "GlobalState's shared raw-handle contract is documented on GlobalState"
110)]
111impl GlobalState {
112    pub const unsafe fn from_raw(raw: NonNull<RawGlobalState>) -> Self {
113        Self { raw }
114    }
115
116    pub unsafe fn main_thread(&self) -> Thread {
117        unsafe {
118            Thread::from_raw(NonNull::new_unchecked(
119                self.as_ptr().as_ref().unwrap_unchecked().main_thread,
120            ))
121        }
122    }
123
124    pub fn encode_pointer(&self, pointer: usize) -> usize {
125        let keys = unsafe { self.as_ptr().as_ref().unwrap_unchecked().ptr_enc_key };
126
127        ((keys[0] as usize)
128            .wrapping_mul(pointer)
129            .wrapping_add(keys[2] as usize))
130            ^ ((keys[1] as usize)
131                .wrapping_mul(pointer)
132                .wrapping_add(keys[3] as usize))
133    }
134
135    pub fn registry(&self) -> TValue {
136        unsafe { TValue::from_raw(NonNull::new_unchecked(&raw mut (*self.as_ptr()).registry)) }
137    }
138
139    pub fn pseudo_temp(&self) -> TValue {
140        unsafe {
141            TValue::from_raw(NonNull::new_unchecked(
142                &raw mut (*self.as_ptr()).pseudo_temp,
143            ))
144        }
145    }
146
147    pub fn registry_free(&self) -> i32 {
148        unsafe { (*self.as_ptr()).registry_free }
149    }
150
151    pub fn set_registry_free(&self, registry_free: i32) {
152        unsafe {
153            (*self.as_ptr()).registry_free = registry_free;
154        }
155    }
156
157    pub(crate) fn weak_registry(&self) -> TValue {
158        unsafe {
159            TValue::from_raw(NonNull::new_unchecked(
160                &raw mut (*self.as_ptr()).weak_registry,
161            ))
162        }
163    }
164
165    pub(crate) fn weak_registry_free(&self) -> i32 {
166        unsafe { (*self.as_ptr()).weak_registry_free }
167    }
168
169    pub(crate) fn set_weak_registry_free(&self, registry_free: i32) {
170        unsafe {
171            (*self.as_ptr()).weak_registry_free = registry_free;
172        }
173    }
174
175    pub(crate) fn embedder_gc(&self) -> Option<EmbedderGc> {
176        unsafe { (*self.as_ptr()).embedder_gc }
177    }
178
179    pub(crate) fn set_embedder_gc(&self, callback: Option<EmbedderGc>) {
180        unsafe {
181            (*self.as_ptr()).embedder_gc = callback;
182        }
183    }
184}
185
186impl Sealed for GlobalState {}
187
188impl RawHandle for GlobalState {
189    type Raw = RawGlobalState;
190
191    fn as_ptr(&self) -> *mut Self::Raw {
192        self.raw.as_ptr()
193    }
194}
195
196impl AsRef<GlobalState> for GlobalState {
197    fn as_ref(&self) -> &GlobalState {
198        self
199    }
200}
201
202pub(crate) const THREAD_STATUS_OK: u8 = 0;
203pub(crate) const THREAD_STATUS_YIELD: u8 = 1;
204pub(crate) const THREAD_STATUS_ERR_RUN: u8 = 2;
205pub(crate) const THREAD_STATUS_ERR_SYNTAX: u8 = 3;
206pub(crate) const THREAD_STATUS_ERR_MEM: u8 = 4;
207pub(crate) const THREAD_STATUS_ERR_ERR: u8 = 5;
208pub(crate) const THREAD_STATUS_BREAK: u8 = 6;
209pub(crate) const THREAD_STATUS_SCHEDULED_REENTRY: u8 = 0x7f;
210
211pub const LUA_MEMERRMSG: &[u8] = b"not enough memory";
212pub const LUA_ERRERRMSG: &[u8] = b"error in error handling";
213
214/// `LUA_EXECUTION_CALLBACK_STORAGE`
215pub(crate) const LUA_EXECUTION_CALLBACK_STORAGE: usize = 512;
216
217pub const EXTRA_STACK: usize = 5;
218pub const BASIC_CI_SIZE: usize = 8;
219pub const BASIC_STACK_SIZE: usize = 2 * LUA_MIN_STACK;
220pub const INITIAL_STACK_SIZE: usize = BASIC_STACK_SIZE + EXTRA_STACK;
221pub const MAX_NATIVE_CALLS_HARD: u16 = LUAI_MAX_NATIVE_CALLS + (LUAI_MAX_NATIVE_CALLS >> 3);
222pub const LUA_CALLINFO_RETURN: u32 = 1 << 0;
223pub const LUA_CALLINFO_HANDLE: u32 = 1 << 1;
224pub const LUA_CALLINFO_NATIVE: u32 = 1 << 2;
225pub const LUA_CALLINFO_OP_YIELD: u32 = 1 << 3;
226
227pub const LUA_OK: i32 = THREAD_STATUS_OK as i32;
228pub const LUA_YIELD: i32 = THREAD_STATUS_YIELD as i32;
229pub const LUA_ERRRUN: i32 = THREAD_STATUS_ERR_RUN as i32;
230pub const LUA_ERRSYNTAX: i32 = THREAD_STATUS_ERR_SYNTAX as i32;
231pub const LUA_ERRMEM: i32 = THREAD_STATUS_ERR_MEM as i32;
232pub const LUA_ERRERR: i32 = THREAD_STATUS_ERR_ERR as i32;
233pub const LUA_BREAK: i32 = THREAD_STATUS_BREAK as i32;