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}