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