lust/vm/
mod.rs

1mod corelib;
2mod cycle;
3#[cfg(feature = "std")]
4pub mod stdlib;
5mod task;
6pub(super) use self::task::{TaskId, TaskInstance, TaskManager, TaskState};
7pub(super) use crate::ast::{FieldOwnership, StructDef};
8pub(super) use crate::bytecode::{
9    FieldStorage, Function, Instruction, NativeCallResult, Register, StructLayout, TaskHandle,
10    Value,
11};
12pub(super) use crate::error::StackFrame;
13pub(super) use crate::jit::{
14    JitCompiler, JitState, TraceOptimizer, TraceRecorder, MAX_TRACE_LENGTH,
15};
16pub(super) use crate::number::{
17    float_abs, float_ceil, float_clamp, float_floor, float_from_int, float_round, float_sqrt,
18    int_from_float, int_from_usize, LustFloat,
19};
20pub(super) use crate::{LustError, Result};
21pub(super) use alloc::{
22    format,
23    rc::Rc,
24    string::{String, ToString},
25    vec,
26    vec::Vec,
27};
28use core::cell::RefCell;
29use hashbrown::HashMap;
30mod api;
31mod execution;
32mod tasks;
33mod tracing;
34pub use self::api::{NativeExport, NativeExportParam};
35#[cfg(feature = "std")]
36thread_local! {
37    static CURRENT_VM_STACK: RefCell<Vec<*mut VM>> = RefCell::new(Vec::new());
38}
39
40#[cfg(not(feature = "std"))]
41struct VmStack {
42    inner: core::cell::UnsafeCell<Option<Vec<*mut VM>>>,
43}
44
45#[cfg(not(feature = "std"))]
46impl VmStack {
47    const fn new() -> Self {
48        Self {
49            inner: core::cell::UnsafeCell::new(None),
50        }
51    }
52
53    fn with_mut<F, R>(&self, f: F) -> R
54    where
55        F: FnOnce(&mut Vec<*mut VM>) -> R,
56    {
57        let vec = self.ensure_vec();
58        f(vec)
59    }
60
61    fn with_ref<F, R>(&self, f: F) -> R
62    where
63        F: FnOnce(&Vec<*mut VM>) -> R,
64    {
65        let vec = self.ensure_vec();
66        f(vec)
67    }
68
69    fn ensure_vec(&self) -> &mut Vec<*mut VM> {
70        unsafe {
71            let slot = &mut *self.inner.get();
72            if slot.is_none() {
73                *slot = Some(Vec::new());
74            }
75            slot.as_mut().unwrap()
76        }
77    }
78}
79
80#[cfg(not(feature = "std"))]
81unsafe impl Sync for VmStack {}
82
83#[cfg(not(feature = "std"))]
84static VM_STACK: VmStack = VmStack::new();
85
86#[cfg(feature = "std")]
87fn with_vm_stack_ref<F, R>(f: F) -> R
88where
89    F: FnOnce(&Vec<*mut VM>) -> R,
90{
91    CURRENT_VM_STACK.with(|stack| {
92        let stack = stack.borrow();
93        f(&stack)
94    })
95}
96
97#[cfg(feature = "std")]
98fn with_vm_stack_mut<F, R>(f: F) -> R
99where
100    F: FnOnce(&mut Vec<*mut VM>) -> R,
101{
102    CURRENT_VM_STACK.with(|stack| {
103        let mut stack = stack.borrow_mut();
104        f(&mut stack)
105    })
106}
107
108#[cfg(not(feature = "std"))]
109fn with_vm_stack_ref<F, R>(f: F) -> R
110where
111    F: FnOnce(&Vec<*mut VM>) -> R,
112{
113    VM_STACK.with_ref(f)
114}
115
116#[cfg(not(feature = "std"))]
117fn with_vm_stack_mut<F, R>(f: F) -> R
118where
119    F: FnOnce(&mut Vec<*mut VM>) -> R,
120{
121    VM_STACK.with_mut(f)
122}
123
124pub(crate) fn push_vm_ptr(vm: *mut VM) {
125    with_vm_stack_mut(|stack| stack.push(vm));
126}
127
128pub(crate) fn pop_vm_ptr() {
129    with_vm_stack_mut(|stack| {
130        stack.pop();
131    });
132}
133
134#[cfg(feature = "std")]
135pub(super) fn with_vm_stack<F, R>(f: F) -> R
136where
137    F: FnOnce(&Vec<*mut VM>) -> R,
138{
139    with_vm_stack_ref(f)
140}
141
142#[cfg(not(feature = "std"))]
143pub(super) fn with_vm_stack<F, R>(f: F) -> R
144where
145    F: FnOnce(&Vec<*mut VM>) -> R,
146{
147    with_vm_stack_ref(f)
148}
149
150pub(super) const TO_STRING_TRAIT: &str = "ToString";
151pub(super) const TO_STRING_METHOD: &str = "to_string";
152pub struct VM {
153    pub(super) functions: Vec<Function>,
154    pub(super) natives: HashMap<String, Value>,
155    pub(super) globals: HashMap<String, Value>,
156    pub(super) call_stack: Vec<CallFrame>,
157    pub(super) max_stack_depth: usize,
158    pub(super) pending_return_value: Option<Value>,
159    pub(super) pending_return_dest: Option<Register>,
160    pub(super) jit: JitState,
161    pub(super) trace_recorder: Option<TraceRecorder>,
162    pub(super) side_trace_context: Option<(crate::jit::TraceId, usize)>,
163    pub(super) skip_next_trace_record: bool,
164    pub(super) trait_impls: HashMap<(String, String), bool>,
165    pub(super) struct_tostring_cache: HashMap<usize, Rc<String>>,
166    pub(super) struct_metadata: HashMap<String, RuntimeStructInfo>,
167    pub(super) call_until_depth: Option<usize>,
168    pub(super) task_manager: TaskManager,
169    pub(super) current_task: Option<TaskId>,
170    pub(super) pending_task_signal: Option<TaskSignal>,
171    pub(super) last_task_signal: Option<TaskSignal>,
172    pub(super) cycle_collector: cycle::CycleCollector,
173    pub(super) exported_natives: Vec<NativeExport>,
174    pub(super) export_prefix_stack: Vec<String>,
175}
176
177#[derive(Debug, Clone)]
178pub(super) struct CallFrame {
179    pub(super) function_idx: usize,
180    pub(super) ip: usize,
181    pub(super) registers: [Value; 256],
182    #[allow(dead_code)]
183    pub(super) base_register: usize,
184    pub(super) return_dest: Option<Register>,
185    pub(super) upvalues: Vec<Value>,
186}
187
188#[derive(Debug, Clone)]
189pub(super) struct RuntimeStructInfo {
190    pub layout: Rc<StructLayout>,
191}
192
193#[derive(Debug, Clone)]
194pub(super) enum TaskSignal {
195    Yield { dest: Register, value: Value },
196    Stop { value: Value },
197}
198
199impl Default for VM {
200    fn default() -> Self {
201        Self::new()
202    }
203}