1use super::*;
2use crate::bytecode::ValueKey;
3use core::{array, ptr};
4impl VM {
5 fn lua_table_map(value: &Value) -> Option<Value> {
6 if let Value::Enum {
7 enum_name,
8 variant,
9 values,
10 } = value
11 {
12 if enum_name == "LuaValue" && variant == "Table" {
13 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
14 if let Some(map) = inner.struct_get_field("table") {
15 return Some(map);
16 }
17 }
18 }
19 }
20
21 if let Value::Struct { name, .. } = value {
22 if name == "LuaTable" {
23 if let Some(map) = value.struct_get_field("table") {
24 return Some(map);
25 }
26 }
27 }
28
29 None
30 }
31
32 fn lua_table_key_value(value: &Value) -> Value {
33 if let Value::Enum {
34 enum_name,
35 variant,
36 values,
37 } = value
38 {
39 if enum_name == "LuaValue" {
40 return match variant.as_str() {
41 "Nil" => Value::Nil,
42 "Bool" | "Int" | "Float" | "String" | "Table" | "Function" | "LightUserdata"
43 | "Userdata" | "Thread" => values
44 .as_ref()
45 .and_then(|v| v.get(0))
46 .cloned()
47 .unwrap_or(Value::Nil),
48 _ => value.clone(),
49 };
50 }
51 }
52 value.clone()
53 }
54
55 pub(super) fn push_current_vm(&mut self) {
56 let ptr = self as *mut VM;
57 crate::vm::push_vm_ptr(ptr);
58 }
59
60 pub(super) fn pop_current_vm(&mut self) {
61 crate::vm::pop_vm_ptr();
62 }
63
64 pub(super) fn run(&mut self) -> Result<Value> {
65 loop {
66 if let Some(target_depth) = self.call_until_depth {
67 if self.call_stack.len() == target_depth {
68 if let Some(return_value) = self.pending_return_value.take() {
69 self.call_until_depth = None;
70 return Ok(return_value);
71 }
72 }
73 }
74
75 if let Some(return_value) = self.pending_return_value.take() {
76 if let Some(dest_reg) = self.pending_return_dest.take() {
77 self.set_register(dest_reg, return_value)?;
78 }
79 }
80
81 if self.current_task.is_some() {
82 if let Some(signal) = self.pending_task_signal.take() {
83 self.last_task_signal = Some(signal);
84 return Ok(Value::Nil);
85 }
86 }
87
88 if self.call_stack.len() > self.max_stack_depth {
89 return Err(LustError::RuntimeError {
90 message: "Stack overflow".to_string(),
91 });
92 }
93
94 let executing_frame_index =
95 self.call_stack
96 .len()
97 .checked_sub(1)
98 .ok_or_else(|| LustError::RuntimeError {
99 message: "Empty call stack".to_string(),
100 })?;
101 let frame = self
102 .call_stack
103 .last_mut()
104 .ok_or_else(|| LustError::RuntimeError {
105 message: "Empty call stack".to_string(),
106 })?;
107 let (instruction, ip_before_execution, func_idx) = {
108 let func = &self.functions[frame.function_idx];
109 if frame.ip >= func.chunk.instructions.len() {
110 self.call_stack.pop();
111 if self.call_stack.is_empty() {
112 return Ok(Value::Nil);
113 }
114
115 continue;
116 }
117
118 let instruction = func.chunk.instructions[frame.ip];
119 frame.ip += 1;
120 let ip_before_execution = frame.ip;
121 let func_idx = frame.function_idx;
122 (instruction, ip_before_execution, func_idx)
123 };
124 let (should_check_jit, loop_start_ip) = if let Instruction::Jump(offset) = instruction {
125 if offset < 0 {
126 let current_frame = self.call_stack.last().unwrap();
127 let jump_target = (current_frame.ip as isize + offset as isize) as usize;
128 (true, jump_target)
129 } else {
130 (false, 0)
131 }
132 } else {
133 (false, 0)
134 };
135 if should_check_jit && self.jit.enabled {
136 let count = self.jit.profiler.record_backedge(func_idx, loop_start_ip);
137 if let Some(trace_id) = self
138 .jit
139 .root_traces
140 .get(&(func_idx, loop_start_ip))
141 .copied()
142 {
143 let frame = self.call_stack.last_mut().unwrap();
144 let registers_ptr = frame.registers.as_mut_ptr();
145 let entry = self.jit.get_trace(trace_id).map(|t| t.entry);
146 if let Some(entry_fn) = entry {
147 crate::jit::log(|| {
148 format!(
149 "▶️ JIT: Executing trace #{} at func {} ip {}",
150 trace_id.0, func_idx, loop_start_ip
151 )
152 });
153
154 let trace_gas_cost = self
155 .jit
156 .get_trace(trace_id)
157 .map(|t| {
158 let cost = t.trace.ops.len()
159 + t.trace.preamble.len()
160 + t.trace.postamble.len();
161 core::cmp::max(1, cost) as u64
162 })
163 .unwrap_or(1);
164 self.budgets.charge_gas(trace_gas_cost)?;
165
166 #[cfg(target_arch = "x86_64")]
168 let rsp_before: usize;
169 #[cfg(target_arch = "x86_64")]
170 unsafe { core::arch::asm!("mov {}, rsp", out(reg) rsp_before) };
171
172 let result = entry_fn(registers_ptr, self as *mut VM, ptr::null());
173
174 #[cfg(target_arch = "x86_64")]
175 let rsp_after: usize;
176 #[cfg(target_arch = "x86_64")]
177 unsafe { core::arch::asm!("mov {}, rsp", out(reg) rsp_after) };
178
179 #[cfg(target_arch = "x86_64")]
180 let rsp_diff = rsp_after as isize - rsp_before as isize;
181 crate::jit::log(|| {
182 #[cfg(target_arch = "x86_64")]
183 return format!("🎯 JIT: Trace #{} execution result: {} (RSP before: {:x}, after: {:x}, diff: {})",
184 trace_id.0, result, rsp_before, rsp_after, rsp_diff);
185 #[cfg(not(target_arch = "x86_64"))]
186 return format!("🎯 JIT: Trace #{} execution result: {}", trace_id.0, result);
187 });
188
189 if result == 0 {
190 if self.current_task.is_some() && self.pending_task_signal.is_some() {
191 if let Some(frame) = self.call_stack.last_mut() {
192 frame.ip = ip_before_execution.saturating_sub(1);
193 }
194 continue;
195 }
196
197 if let Some(frame) = self.call_stack.last_mut() {
198 frame.ip = loop_start_ip;
199 }
200
201 continue;
202 } else if result > 0 {
203 let guard_index = (result - 1) as usize;
204 let side_trace_id = self
205 .jit
206 .get_trace(trace_id)
207 .and_then(|t| t.guards.get(guard_index))
208 .and_then(|g| g.side_trace);
209 if let Some(side_trace_id) = side_trace_id {
210 crate::jit::log(|| {
211 format!(
212 "🌳 JIT: Executing side trace #{} for guard #{}",
213 side_trace_id.0, guard_index
214 )
215 });
216 let frame = self.call_stack.last_mut().unwrap();
217 let registers_ptr = frame.registers.as_mut_ptr();
218 let side_entry = self.jit.get_trace(side_trace_id).map(|t| t.entry);
219 if let Some(side_entry_fn) = side_entry {
220 let side_trace_gas_cost = self
221 .jit
222 .get_trace(side_trace_id)
223 .map(|t| {
224 let cost = t.trace.ops.len()
225 + t.trace.preamble.len()
226 + t.trace.postamble.len();
227 core::cmp::max(1, cost) as u64
228 })
229 .unwrap_or(1);
230 self.budgets.charge_gas(side_trace_gas_cost)?;
231 let side_result =
232 side_entry_fn(registers_ptr, self as *mut VM, ptr::null());
233 if side_result == 0 {
234 crate::jit::log(|| {
235 format!(
236 "✅ JIT: Side trace #{} executed successfully",
237 side_trace_id.0
238 )
239 });
240 } else {
241 crate::jit::log(|| {
242 format!(
243 "⚠️ JIT: Side trace #{} failed, falling back to interpreter",
244 side_trace_id.0
245 )
246 });
247 }
248 }
249 } else {
250 if let Some(trace) = self.jit.get_trace(trace_id) {
251 if let Some(g) = trace.guards.get(guard_index) {
252 if g.bailout_ip != 0 {
253 continue;
254 }
255 }
256 }
257
258 self.handle_guard_failure(trace_id, guard_index, func_idx)?;
259 self.jit.root_traces.remove(&(func_idx, loop_start_ip));
260 }
261 } else {
262 crate::jit::log(|| {
263 "⚠️ JIT: Trace execution failed (unknown error)".to_string()
264 });
265 if let Some(frame) = self.call_stack.last_mut() {
266 frame.ip = loop_start_ip;
267 }
268
269 self.jit.root_traces.remove(&(func_idx, loop_start_ip));
270 }
271 }
272 } else {
273 let is_side_trace = self.side_trace_context.is_some();
274 if is_side_trace {
275 if let Some(recorder) = &self.trace_recorder {
276 if !recorder.is_recording() {
277 crate::jit::log(|| {
278 format!(
279 "📝 JIT: Trace recording complete - {} ops recorded",
280 recorder.trace.ops.len()
281 )
282 });
283 let recorder = self.trace_recorder.take().unwrap();
284 let mut trace = recorder.finish();
285 let side_trace_ctx = self.side_trace_context.take().unwrap();
286 let mut optimizer = TraceOptimizer::new();
287 let hoisted_constants = optimizer.optimize(&mut trace);
288 let (parent_trace_id, guard_index) = side_trace_ctx;
289 crate::jit::log(|| {
290 format!(
291 "⚙️ JIT: Compiling side trace (parent: #{}, guard: {})...",
292 parent_trace_id.0, guard_index
293 )
294 });
295 let trace_id = self.jit.alloc_trace_id();
296 match JitCompiler::new().compile_trace(
297 &trace,
298 trace_id,
299 Some(parent_trace_id),
300 hoisted_constants.clone(),
301 ) {
302 Ok(compiled_trace) => {
303 crate::jit::log(|| {
304 format!(
305 "✅ JIT: Side trace #{} compiled successfully!",
306 trace_id.0
307 )
308 });
309 if let Some(parent) =
310 self.jit.get_trace_mut(parent_trace_id)
311 {
312 if guard_index < parent.guards.len() {
313 parent.guards[guard_index].side_trace =
314 Some(trace_id);
315 crate::jit::log(|| {
316 format!(
317 "🔗 JIT: Linked side trace #{} to parent trace #{} guard #{}",
318 trace_id.0, parent_trace_id.0, guard_index
319 )
320 });
321 }
322 }
323
324 self.jit.store_side_trace(compiled_trace);
325 }
326
327 Err(e) => {
328 crate::jit::log(|| {
329 format!("❌ JIT: Side trace compilation failed: {}", e)
330 });
331 }
332 }
333 }
334 }
335 } else {
336 if let Some(recorder) = &mut self.trace_recorder {
337 if recorder.is_recording() && count > crate::jit::HOT_THRESHOLD + 1 {
338 crate::jit::log(|| {
339 format!(
340 "📝 JIT: Trace recording complete - {} ops recorded",
341 recorder.trace.ops.len()
342 )
343 });
344 let recorder = self.trace_recorder.take().unwrap();
345 let mut trace = recorder.finish();
346 let mut optimizer = TraceOptimizer::new();
347 let hoisted_constants = optimizer.optimize(&mut trace);
348 crate::jit::log(|| "⚙️ JIT: Compiling root trace...".to_string());
349 let trace_id = self.jit.alloc_trace_id();
350 match JitCompiler::new().compile_trace(
351 &trace,
352 trace_id,
353 None,
354 hoisted_constants.clone(),
355 ) {
356 Ok(compiled_trace) => {
357 crate::jit::log(|| {
358 format!(
359 "✅ JIT: Trace #{} compiled successfully!",
360 trace_id.0
361 )
362 });
363 crate::jit::log(|| {
364 "🚀 JIT: Future iterations will use native code!"
365 .to_string()
366 });
367 self.jit.store_root_trace(
368 func_idx,
369 loop_start_ip,
370 compiled_trace,
371 );
372 }
373
374 Err(e) => {
375 crate::jit::log(|| {
376 format!("❌ JIT: Trace compilation failed: {}", e)
377 });
378 }
379 }
380 }
381 }
382
383 if count == crate::jit::HOT_THRESHOLD + 1 {
384 crate::jit::log(|| {
385 format!(
386 "🔥 JIT: Hot loop detected at func {} ip {} - starting trace recording!",
387 func_idx, loop_start_ip
388 )
389 });
390 let mut recorder =
391 TraceRecorder::new(func_idx, loop_start_ip, MAX_TRACE_LENGTH);
392 {
394 let frame = self.call_stack.last().unwrap();
395 let func = &self.functions[func_idx];
396 recorder.specialize_trace_inputs(&frame.registers, func);
397 }
398 self.trace_recorder = Some(recorder);
399 self.skip_next_trace_record = true;
400 }
401 }
402 }
403 }
404
405 self.budgets.charge_gas(1)?;
406 match instruction {
407 Instruction::LoadNil(dest) => {
408 self.set_register(dest, Value::Nil)?;
409 }
410
411 Instruction::LoadBool(dest, value) => {
412 self.set_register(dest, Value::Bool(value))?;
413 }
414
415 Instruction::LoadConst(dest, const_idx) => {
416 let constant = {
417 let func = &self.functions[func_idx];
418 func.chunk.constants[const_idx as usize].clone()
419 };
420 self.set_register(dest, constant)?;
421 }
422
423 Instruction::LoadGlobal(dest, name_idx) => {
424 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
425 let name = func.chunk.constants[name_idx as usize]
426 .as_string()
427 .ok_or_else(|| LustError::RuntimeError {
428 message: "Global name must be a string".to_string(),
429 })?;
430 if let Some(value) = self.globals.get(name) {
431 self.set_register(dest, value.clone())?;
432 } else if let Some(value) = self.natives.get(name) {
433 self.set_register(dest, value.clone())?;
434 } else {
435 if let Some((_, value)) =
436 self.globals.iter().find(|(key, _)| key.as_str() == name)
437 {
438 self.set_register(dest, value.clone())?;
439 } else if let Some((_, value)) =
440 self.natives.iter().find(|(key, _)| key.as_str() == name)
441 {
442 self.set_register(dest, value.clone())?;
443 } else {
444 return Err(LustError::RuntimeError {
445 message: format!("Undefined global: {}", name),
446 });
447 }
448 }
449 }
450
451 Instruction::StoreGlobal(name_idx, src) => {
452 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
453 let name = func.chunk.constants[name_idx as usize]
454 .as_string()
455 .ok_or_else(|| LustError::RuntimeError {
456 message: "Global name must be a string".to_string(),
457 })?;
458 let value = self.get_register(src)?.clone();
459 self.globals.insert(name.to_string(), value);
460 }
461
462 Instruction::Move(dest, src) => {
463 let value = self.get_register(src)?.clone();
464 self.set_register(dest, value)?;
465 }
466
467 Instruction::Add(dest, lhs, rhs) => {
468 self.binary_op(dest, lhs, rhs, |l, r| match (l, r) {
469 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a + b)),
470 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a + b)),
471 (Value::Int(a), Value::Float(b)) => {
472 Ok(Value::Float(float_from_int(*a) + *b))
473 }
474 (Value::Float(a), Value::Int(b)) => {
475 Ok(Value::Float(*a + float_from_int(*b)))
476 }
477 _ => Err(LustError::RuntimeError {
478 message: format!("Cannot add {:?} and {:?}", l, r),
479 }),
480 })?;
481 }
482
483 Instruction::Sub(dest, lhs, rhs) => {
484 self.binary_op(dest, lhs, rhs, |l, r| match (l, r) {
485 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a - b)),
486 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a - b)),
487 (Value::Int(a), Value::Float(b)) => {
488 Ok(Value::Float(float_from_int(*a) - *b))
489 }
490 (Value::Float(a), Value::Int(b)) => {
491 Ok(Value::Float(*a - float_from_int(*b)))
492 }
493 _ => Err(LustError::RuntimeError {
494 message: format!("Cannot subtract {:?} and {:?}", l, r),
495 }),
496 })?;
497 }
498
499 Instruction::Mul(dest, lhs, rhs) => {
500 self.binary_op(dest, lhs, rhs, |l, r| match (l, r) {
501 (Value::Int(a), Value::Int(b)) => Ok(Value::Int(a * b)),
502 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(a * b)),
503 (Value::Int(a), Value::Float(b)) => {
504 Ok(Value::Float(float_from_int(*a) * *b))
505 }
506 (Value::Float(a), Value::Int(b)) => {
507 Ok(Value::Float(*a * float_from_int(*b)))
508 }
509 _ => Err(LustError::RuntimeError {
510 message: format!("Cannot multiply {:?} and {:?}", l, r),
511 }),
512 })?;
513 }
514
515 Instruction::Div(dest, lhs, rhs) => {
516 self.binary_op(dest, lhs, rhs, |l, r| match (l, r) {
517 (Value::Int(a), Value::Int(b)) => {
518 if *b == 0 {
519 Err(LustError::RuntimeError {
520 message: "Division by zero".to_string(),
521 })
522 } else {
523 Ok(Value::Int(a / b))
524 }
525 }
526
527 (Value::Float(a), Value::Float(b)) => Ok(Value::Float(*a / *b)),
528 (Value::Int(a), Value::Float(b)) => {
529 Ok(Value::Float(float_from_int(*a) / *b))
530 }
531 (Value::Float(a), Value::Int(b)) => {
532 Ok(Value::Float(*a / float_from_int(*b)))
533 }
534 _ => Err(LustError::RuntimeError {
535 message: format!("Cannot divide {:?} and {:?}", l, r),
536 }),
537 })?;
538 }
539
540 Instruction::Mod(dest, lhs, rhs) => {
541 self.binary_op(dest, lhs, rhs, |l, r| match (l, r) {
542 (Value::Int(a), Value::Int(b)) => {
543 if *b == 0 {
544 Err(LustError::RuntimeError {
545 message: "Modulo by zero".to_string(),
546 })
547 } else {
548 Ok(Value::Int(a % b))
549 }
550 }
551
552 (Value::Float(a), Value::Float(b)) => {
553 if *b == 0.0 {
554 Err(LustError::RuntimeError {
555 message: "Modulo by zero".to_string(),
556 })
557 } else {
558 Ok(Value::Float(a % b))
559 }
560 }
561
562 (Value::Int(a), Value::Float(b)) => {
563 if *b == 0.0 {
564 Err(LustError::RuntimeError {
565 message: "Modulo by zero".to_string(),
566 })
567 } else {
568 Ok(Value::Float(float_from_int(*a) % *b))
569 }
570 }
571
572 (Value::Float(a), Value::Int(b)) => {
573 if *b == 0 {
574 Err(LustError::RuntimeError {
575 message: "Modulo by zero".to_string(),
576 })
577 } else {
578 Ok(Value::Float(*a % float_from_int(*b)))
579 }
580 }
581
582 _ => Err(LustError::RuntimeError {
583 message: format!("Cannot modulo {:?} and {:?}", l, r),
584 }),
585 })?;
586 }
587
588 Instruction::Neg(dest, src) => {
589 let value = self.get_register(src)?;
590 let result = match value {
591 Value::Int(i) => Value::Int(-i),
592 Value::Float(f) => Value::Float(-f),
593 _ => {
594 return Err(LustError::RuntimeError {
595 message: format!("Cannot negate {:?}", value),
596 })
597 }
598 };
599 self.set_register(dest, result)?;
600 }
601
602 Instruction::Eq(dest, lhs, rhs) => {
603 let left = self.get_register(lhs)?;
604 let right = self.get_register(rhs)?;
605 self.set_register(dest, Value::Bool(left == right))?;
606 }
607
608 Instruction::Ne(dest, lhs, rhs) => {
609 let left = self.get_register(lhs)?;
610 let right = self.get_register(rhs)?;
611 self.set_register(dest, Value::Bool(left != right))?;
612 }
613
614 Instruction::Lt(dest, lhs, rhs) => {
615 self.comparison_op(dest, lhs, rhs, |l, r| l < r)?;
616 }
617
618 Instruction::Le(dest, lhs, rhs) => {
619 self.comparison_op(dest, lhs, rhs, |l, r| l <= r)?;
620 }
621
622 Instruction::Gt(dest, lhs, rhs) => {
623 self.comparison_op(dest, lhs, rhs, |l, r| l > r)?;
624 }
625
626 Instruction::Ge(dest, lhs, rhs) => {
627 self.comparison_op(dest, lhs, rhs, |l, r| l >= r)?;
628 }
629
630 Instruction::And(dest, lhs, rhs) => {
631 let left = self.get_register(lhs)?;
632 let right = self.get_register(rhs)?;
633 let result = Value::Bool(left.is_truthy() && right.is_truthy());
634 self.set_register(dest, result)?;
635 }
636
637 Instruction::Or(dest, lhs, rhs) => {
638 let left = self.get_register(lhs)?;
639 let right = self.get_register(rhs)?;
640 let result = Value::Bool(left.is_truthy() || right.is_truthy());
641 self.set_register(dest, result)?;
642 }
643
644 Instruction::Not(dest, src) => {
645 let value = self.get_register(src)?;
646 self.set_register(dest, Value::Bool(!value.is_truthy()))?;
647 }
648
649 Instruction::Jump(offset) => {
650 let frame = self.call_stack.last_mut().unwrap();
651 frame.ip = (frame.ip as isize + offset as isize) as usize;
652 }
653
654 Instruction::JumpIf(cond, offset) => {
655 let condition = self.get_register(cond)?;
656 if condition.is_truthy() {
657 let frame = self.call_stack.last_mut().unwrap();
658 frame.ip = (frame.ip as isize + offset as isize) as usize;
659 }
660 }
661
662 Instruction::JumpIfNot(cond, offset) => {
663 let condition = self.get_register(cond)?;
664 if !condition.is_truthy() {
665 let frame = self.call_stack.last_mut().unwrap();
666 frame.ip = (frame.ip as isize + offset as isize) as usize;
667 }
668 }
669
670 Instruction::Call(func_reg, first_arg, arg_count, dest_reg) => {
671 let mut func_value = self.get_register(func_reg)?.clone();
672 let needs_call_value = {
680 let mut check_value = &func_value;
681 if let Value::Enum { enum_name, variant, values } = &func_value {
683 if enum_name == "LuaValue" && (variant == "Table" || variant == "Userdata") {
684 if let Some(inner) = values.as_ref().and_then(|v| v.get(0)) {
685 check_value = inner;
686 }
687 }
688 }
689 if let Value::Struct { name, .. } = check_value {
691 (name == "LuaTable" || name == "LuaUserdata") &&
692 check_value.struct_get_field("metamethods").is_some()
693 } else {
694 false
695 }
696 };
697
698 if needs_call_value {
699 let mut args = Vec::new();
702 for i in 0..arg_count {
703 args.push(self.get_register(first_arg + i)?.clone());
704 }
705 let result = self.call_value(&func_value, args)?;
706 self.set_register(dest_reg, result)?;
707 continue;
708 } else {
709 if let Value::Enum { enum_name, variant, .. } = &func_value {
711 if enum_name == "LuaValue" && (variant == "Table" || variant == "Userdata") {
712 #[cfg(feature = "std")]
713 eprintln!("DEBUG Instruction::Call: Have LuaValue.{} but needs_call_value=false", variant);
714 }
715 }
716 }
717
718 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
719 loop {
720 let handle = match &func_value {
721 Value::Enum {
722 enum_name,
723 variant,
724 values,
725 } if enum_name == "LuaValue" && variant == "Function" => values
726 .as_ref()
727 .and_then(|vals| vals.get(0))
728 .and_then(|v| v.struct_get_field("handle"))
729 .and_then(|v| v.as_int())
730 .map(|i| i as usize),
731 _ => None,
732 };
733 let Some(handle) = handle else { break };
734 let inner = crate::lua_compat::lookup_lust_function(handle).ok_or_else(|| {
735 LustError::RuntimeError {
736 message: format!(
737 "LuaValue function handle {} was not registered with VM",
738 handle
739 ),
740 }
741 })?;
742 func_value = inner;
743 }
744 match func_value {
745 Value::Function(func_idx) => {
746 let mut args = Vec::new();
747 for i in 0..arg_count {
748 args.push(self.get_register(first_arg + i)?.clone());
749 }
750
751 let mut frame = CallFrame {
752 function_idx: func_idx,
753 ip: 0,
754 registers: array::from_fn(|_| Value::Nil),
755 base_register: 0,
756 return_dest: Some(dest_reg),
757 upvalues: Vec::new(),
758 };
759 for (i, arg) in args.into_iter().enumerate() {
760 frame.registers[i] = arg;
761 }
762
763 self.call_stack.push(frame);
764 }
765
766 Value::Closure {
767 function_idx: func_idx,
768 upvalues,
769 } => {
770 let mut args = Vec::new();
771 for i in 0..arg_count {
772 args.push(self.get_register(first_arg + i)?.clone());
773 }
774
775 let upvalue_values: Vec<Value> =
776 upvalues.iter().map(|uv| uv.get()).collect();
777 let mut frame = CallFrame {
778 function_idx: func_idx,
779 ip: 0,
780 registers: array::from_fn(|_| Value::Nil),
781 base_register: 0,
782 return_dest: Some(dest_reg),
783 upvalues: upvalue_values,
784 };
785 for (i, arg) in args.into_iter().enumerate() {
786 frame.registers[i] = arg;
787 }
788
789 self.call_stack.push(frame);
790 }
791
792 Value::NativeFunction(native_fn) => {
793 let mut args = Vec::new();
794 for i in 0..arg_count {
795 args.push(self.get_register(first_arg + i)?.clone());
796 }
797
798 self.push_current_vm();
799 let outcome = native_fn(&args);
800 self.pop_current_vm();
801 let outcome =
802 outcome.map_err(|e| LustError::RuntimeError { message: e })?;
803 self.handle_native_call_outcome(dest_reg, outcome)?;
804 }
805
806 _ => {
807 return Err(LustError::RuntimeError {
808 message: format!(
809 "Cannot call non-function value: {:?}",
810 func_value
811 ),
812 })
813 }
814 }
815 }
816
817 Instruction::Return(value_reg) => {
818 let return_value = if value_reg == 255 {
819 Value::Nil
820 } else {
821 self.get_register(value_reg)?.clone()
822 };
823 let return_dest = self.call_stack.last().unwrap().return_dest;
824 self.call_stack.pop();
825 if self.call_stack.is_empty() {
826 return Ok(return_value);
827 }
828
829 self.pending_return_value = Some(return_value);
830 self.pending_return_dest = return_dest;
831 }
832
833 Instruction::NewArray(dest, first_elem, count) => {
834 let element_count = count as usize;
835 self.budgets.charge_value_vec(element_count)?;
836 let mut elements = Vec::with_capacity(element_count);
837 for i in 0..count {
838 elements.push(self.get_register(first_elem + i)?.clone());
839 }
840
841 self.set_register(dest, Value::array(elements))?;
842 }
843
844 Instruction::TupleNew(dest, first_elem, count) => {
845 let mut parts = Vec::with_capacity(count as usize);
846 let mut total_elements: usize = 0;
847 for offset in 0..(count as usize) {
848 let value = self.get_register(first_elem + offset as u8)?.clone();
849 total_elements = total_elements.saturating_add(match &value {
850 Value::Tuple(existing) => existing.len(),
851 _ => 1,
852 });
853 parts.push(value);
854 }
855
856 self.budgets.charge_value_vec(total_elements)?;
857 let mut elements = Vec::with_capacity(total_elements);
858 for value in parts {
859 if let Value::Tuple(existing) = value {
860 elements.extend(existing.iter().cloned());
861 } else {
862 elements.push(value);
863 }
864 }
865
866 self.set_register(dest, Value::tuple(elements))?;
867 }
868
869 Instruction::TupleGet(dest, tuple_reg, index) => {
870 let tuple_value = self.get_register(tuple_reg)?.clone();
871 if let Value::Tuple(values) = tuple_value {
872 let idx = index as usize;
873 if idx >= values.len() {
874 return Err(LustError::RuntimeError {
875 message: format!(
876 "Tuple index {} out of bounds (len {})",
877 idx,
878 values.len()
879 ),
880 });
881 }
882
883 let value = values[idx].clone();
884 self.set_register(dest, value)?;
885 } else {
886 return Err(LustError::RuntimeError {
887 message: "Attempted to destructure non-tuple value".to_string(),
888 });
889 }
890 }
891
892 Instruction::NewMap(dest) => {
893 self.set_register(dest, self.new_map_value())?;
894 }
895
896 Instruction::NewStruct(
897 dest,
898 name_idx,
899 first_field_name_idx,
900 first_field,
901 field_count,
902 ) => {
903 self.budgets.charge_value_vec(field_count as usize)?;
904 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
905 let struct_name = func.chunk.constants[name_idx as usize]
906 .as_string()
907 .ok_or_else(|| LustError::RuntimeError {
908 message: "Struct name must be a string".to_string(),
909 })?
910 .to_string();
911 let mut fields = Vec::with_capacity(field_count as usize);
912 for i in 0..field_count {
913 let field_name = func.chunk.constants
914 [(first_field_name_idx + i as u16) as usize]
915 .as_string_rc()
916 .ok_or_else(|| LustError::RuntimeError {
917 message: "Field name must be a string".to_string(),
918 })?;
919 let value = self.get_register(first_field + i)?.clone();
920 fields.push((field_name, value));
921 }
922
923 let struct_value = self.instantiate_struct(&struct_name, fields)?;
924 self.set_register(dest, struct_value)?;
925 }
926
927 Instruction::NewEnumUnit(dest, enum_name_idx, variant_idx) => {
928 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
929 let enum_name = func.chunk.constants[enum_name_idx as usize]
930 .as_string()
931 .ok_or_else(|| LustError::RuntimeError {
932 message: "Enum name must be a string".to_string(),
933 })?
934 .to_string();
935 let variant_name = func.chunk.constants[variant_idx as usize]
936 .as_string()
937 .ok_or_else(|| LustError::RuntimeError {
938 message: "Variant name must be a string".to_string(),
939 })?
940 .to_string();
941 self.set_register(dest, Value::enum_unit(enum_name, variant_name))?;
942 }
943
944 Instruction::NewEnumVariant(
945 dest,
946 enum_name_idx,
947 variant_idx,
948 first_value,
949 value_count,
950 ) => {
951 self.budgets.charge_value_vec(value_count as usize)?;
952 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
953 let enum_name = func.chunk.constants[enum_name_idx as usize]
954 .as_string()
955 .ok_or_else(|| LustError::RuntimeError {
956 message: "Enum name must be a string".to_string(),
957 })?
958 .to_string();
959 let variant_name = func.chunk.constants[variant_idx as usize]
960 .as_string()
961 .ok_or_else(|| LustError::RuntimeError {
962 message: "Variant name must be a string".to_string(),
963 })?
964 .to_string();
965 let mut values = Vec::with_capacity(value_count as usize);
966 for i in 0..value_count {
967 values.push(self.get_register(first_value + i)?.clone());
968 }
969
970 self.set_register(dest, Value::enum_variant(enum_name, variant_name, values))?;
971 }
972
973 Instruction::IsEnumVariant(dest, value_reg, enum_name_idx, variant_idx) => {
974 let value = self.get_register(value_reg)?;
975 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
976 let enum_name = func.chunk.constants[enum_name_idx as usize]
977 .as_string()
978 .ok_or_else(|| LustError::RuntimeError {
979 message: "Enum name must be a string".to_string(),
980 })?;
981 let variant_name = func.chunk.constants[variant_idx as usize]
982 .as_string()
983 .ok_or_else(|| LustError::RuntimeError {
984 message: "Variant name must be a string".to_string(),
985 })?;
986 let is_variant = value.is_enum_variant(enum_name, variant_name);
987 self.set_register(dest, Value::Bool(is_variant))?;
988 }
989
990 Instruction::GetEnumValue(dest, enum_reg, index) => {
991 let enum_value = self.get_register(enum_reg)?;
992 if let Some((_, _, Some(values))) = enum_value.as_enum() {
993 if (index as usize) < values.len() {
994 self.set_register(dest, values[index as usize].clone())?;
995 } else {
996 return Err(LustError::RuntimeError {
997 message: format!(
998 "Enum value index {} out of bounds (has {} values)",
999 index,
1000 values.len()
1001 ),
1002 });
1003 }
1004 } else {
1005 return Err(LustError::RuntimeError {
1006 message: "GetEnumValue requires an enum variant with values"
1007 .to_string(),
1008 });
1009 }
1010 }
1011
1012 Instruction::GetField(dest, obj, field_idx) => {
1013 let object = self.get_register(obj)?;
1014 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1015 let field_name = func.chunk.constants[field_idx as usize]
1016 .as_string_rc()
1017 .ok_or_else(|| LustError::RuntimeError {
1018 message: "Field name must be a string".to_string(),
1019 })?;
1020 let value = if let Some(map_val) = Self::lua_table_map(object) {
1021 if let Value::Map(map) = map_val {
1022 let raw_key_value = Value::String(field_name.clone());
1023 let key = self.make_hash_key(&Self::lua_table_key_value(&raw_key_value))?;
1024 let borrowed = map.borrow();
1025 borrowed.get(&key).cloned().unwrap_or(Value::Nil)
1026 } else {
1027 Value::Nil
1028 }
1029 } else {
1030 match object {
1031 Value::Struct { .. } => object
1032 .struct_get_field_rc(&field_name)
1033 .unwrap_or(Value::Nil),
1034 Value::Map(map) => {
1035 let key = ValueKey::from(field_name.clone());
1036 map.borrow().get(&key).cloned().unwrap_or(Value::Nil)
1037 }
1038
1039 _ => {
1040 return Err(LustError::RuntimeError {
1041 message: format!(
1042 "Cannot get field '{}' from {:?}",
1043 field_name.as_str(),
1044 object
1045 ),
1046 })
1047 }
1048 }
1049 };
1050 self.set_register(dest, value)?;
1051 }
1052
1053 Instruction::SetField(obj_reg, field_idx, value_reg) => {
1054 let object = self.get_register(obj_reg)?.clone();
1055 let value = self.get_register(value_reg)?.clone();
1056 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1057 let field_name = func.chunk.constants[field_idx as usize]
1058 .as_string_rc()
1059 .ok_or_else(|| LustError::RuntimeError {
1060 message: "Field name must be a string".to_string(),
1061 })?;
1062 let mut invalidate_key: Option<usize> = None;
1063 if let Some(map_val) = Self::lua_table_map(&object) {
1064 if let Value::Map(map) = map_val {
1065 let raw_key_value = Value::String(field_name.clone());
1066 let key = self.make_hash_key(&Self::lua_table_key_value(&raw_key_value))?;
1067 if self.budgets.mem_budget_enabled() && !map.borrow().contains_key(&key)
1068 {
1069 self.budgets.charge_map_entry_estimate()?;
1070 }
1071 map.borrow_mut().insert(key, value);
1072 } else {
1073 return Err(LustError::RuntimeError {
1074 message: format!(
1075 "Cannot set field '{}' on {:?}",
1076 field_name.as_str(),
1077 object
1078 ),
1079 });
1080 }
1081 } else {
1082 match &object {
1083 Value::Struct { .. } => {
1084 invalidate_key = Self::struct_cache_key(&object);
1085 object
1086 .struct_set_field_rc(&field_name, value)
1087 .map_err(|message| LustError::RuntimeError { message })?;
1088 }
1089
1090 Value::Map(map) => {
1091 let key = ValueKey::from(field_name.clone());
1092 if self.budgets.mem_budget_enabled()
1093 && !map.borrow().contains_key(&key)
1094 {
1095 self.budgets.charge_map_entry_estimate()?;
1096 }
1097 map.borrow_mut().insert(key, value);
1098 }
1099
1100 _ => {
1101 return Err(LustError::RuntimeError {
1102 message: format!(
1103 "Cannot set field '{}' on {:?}",
1104 field_name.as_str(),
1105 object
1106 ),
1107 })
1108 }
1109 }
1110 }
1111
1112 if let Some(key) = invalidate_key {
1113 self.struct_tostring_cache.remove(&key);
1114 }
1115 }
1116
1117 Instruction::Concat(dest, lhs, rhs) => {
1118 let (left, right) = {
1119 let frame =
1120 self.call_stack
1121 .last_mut()
1122 .ok_or_else(|| LustError::RuntimeError {
1123 message: "Empty call stack".to_string(),
1124 })?;
1125 let left = frame.registers[lhs as usize].clone();
1126 let right = frame.registers[rhs as usize].clone();
1127 (left, right)
1128 };
1129 let left_str = self.value_to_string_for_concat(&left)?;
1130 let right_str = self.value_to_string_for_concat(&right)?;
1131 let cap = left_str.len().saturating_add(right_str.len());
1132 self.budgets.charge_mem_bytes(cap)?;
1133 let mut combined = String::with_capacity(cap);
1134 combined.push_str(left_str.as_ref());
1135 combined.push_str(right_str.as_ref());
1136 let result = Value::string(combined);
1137 self.set_register(dest, result)?;
1138 }
1139
1140 Instruction::GetIndex(dest, array_reg, index_reg) => {
1141 let collection = self.get_register(array_reg)?.clone();
1142 let index = self.get_register(index_reg)?.clone();
1143 let result = if let Some(map_val) = Self::lua_table_map(&collection) {
1144 if let Value::Map(map) = map_val {
1145 let raw_key = self.make_hash_key(&Self::lua_table_key_value(&index))?;
1146 let borrowed = map.borrow();
1147 borrowed.get(&raw_key).cloned().unwrap_or(Value::Nil)
1148 } else {
1149 return Err(LustError::RuntimeError {
1150 message: format!("Cannot index {:?}", collection.type_of()),
1151 });
1152 }
1153 } else {
1154 match collection {
1155 Value::Array(arr) => {
1156 let idx = index.as_int().ok_or_else(|| LustError::RuntimeError {
1157 message: "Array index must be an integer".to_string(),
1158 })?;
1159 let borrowed = arr.borrow();
1160 if idx < 0 || idx as usize >= borrowed.len() {
1161 return Err(LustError::RuntimeError {
1162 message: format!(
1163 "Array index {} out of bounds (length: {})",
1164 idx,
1165 borrowed.len()
1166 ),
1167 });
1168 }
1169
1170 borrowed[idx as usize].clone()
1171 }
1172
1173 Value::Map(map) => {
1174 let key = self.make_hash_key(&index)?;
1175 map.borrow().get(&key).cloned().unwrap_or(Value::Nil)
1176 }
1177
1178 _ => {
1179 return Err(LustError::RuntimeError {
1180 message: format!("Cannot index {:?}", collection.type_of()),
1181 })
1182 }
1183 }
1184 };
1185 self.set_register(dest, result)?;
1186 }
1187
1188 Instruction::ArrayLen(dest, array_reg) => {
1189 let collection = self.get_register(array_reg)?;
1190 match collection {
1191 Value::Array(arr) => {
1192 let len = int_from_usize(arr.borrow().len());
1193 self.set_register(dest, Value::Int(len))?;
1194 }
1195
1196 _ => {
1197 return Err(LustError::RuntimeError {
1198 message: format!(
1199 "ArrayLen requires array, got {:?}",
1200 collection.type_of()
1201 ),
1202 });
1203 }
1204 }
1205 }
1206
1207 Instruction::CallMethod(
1208 obj_reg,
1209 method_name_idx,
1210 first_arg,
1211 arg_count,
1212 dest_reg,
1213 ) => {
1214 let object = self.get_register(obj_reg)?.clone();
1215 let method_name = {
1216 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1217 func.chunk.constants[method_name_idx as usize]
1218 .as_string()
1219 .ok_or_else(|| LustError::RuntimeError {
1220 message: "Method name must be a string".to_string(),
1221 })?
1222 .to_string()
1223 };
1224 if let Value::Struct {
1225 name: struct_name, ..
1226 } = &object
1227 {
1228 let mangled_name = format!("{}:{}", struct_name, method_name);
1229 if let Some(func_idx) =
1230 self.functions.iter().position(|f| f.name == mangled_name)
1231 {
1232 let mut frame = CallFrame {
1233 function_idx: func_idx,
1234 ip: 0,
1235 registers: array::from_fn(|_| Value::Nil),
1236 base_register: 0,
1237 return_dest: Some(dest_reg),
1238 upvalues: Vec::new(),
1239 };
1240 frame.registers[0] = object.clone();
1241 for i in 0..arg_count {
1242 frame.registers[(i + 1) as usize] =
1243 self.get_register(first_arg + i)?.clone();
1244 }
1245
1246 self.call_stack.push(frame);
1247 continue;
1248 }
1249
1250 let mut candidate_names = vec![mangled_name.clone()];
1251 if let Some(simple) = struct_name.rsplit(|c| c == '.' || c == ':').next() {
1252 candidate_names.push(format!("{}:{}", simple, method_name));
1253 }
1254
1255 let mut handled = false;
1256 for candidate in candidate_names {
1257 let mut resolved = None;
1258 for variant in [candidate.clone(), candidate.replace('.', "::")] {
1259 if let Some((_name, value)) =
1260 self.globals.iter().find(|(name, _)| *name == &variant)
1261 {
1262 resolved = Some(value.clone());
1263 break;
1264 }
1265 if let Some((_name, value)) =
1266 self.natives.iter().find(|(name, _)| *name == &variant)
1267 {
1268 resolved = Some(value.clone());
1269 break;
1270 }
1271 }
1272
1273 if let Some(global_func) = resolved {
1274 let mut call_args = Vec::with_capacity(1 + arg_count as usize);
1275 call_args.push(object.clone());
1276 for i in 0..arg_count {
1277 call_args.push(self.get_register(first_arg + i)?.clone());
1278 }
1279 let result = self.call_value(&global_func, call_args)?;
1280 self.set_register(dest_reg, result)?;
1281 handled = true;
1282 break;
1283 }
1284 }
1285 if handled {
1286 continue;
1287 }
1288 }
1289
1290 let mut args = Vec::new();
1291 for i in 0..arg_count {
1292 args.push(self.get_register(first_arg + i)?.clone());
1293 }
1294
1295 let result = self.call_builtin_method(&object, &method_name, args)?;
1296 self.set_register(dest_reg, result)?;
1297 }
1298
1299 Instruction::Closure(dest, func_idx, first_upvalue_reg, upvalue_count) => {
1300 use crate::bytecode::Upvalue;
1301 self.budgets
1302 .charge_upvalues_estimate(upvalue_count as usize)?;
1303 let mut upvalues = Vec::with_capacity(upvalue_count as usize);
1304 for i in 0..upvalue_count {
1305 let value = self.get_register(first_upvalue_reg + i)?.clone();
1306 upvalues.push(Upvalue::new(value));
1307 }
1308
1309 let closure = Value::Closure {
1310 function_idx: func_idx as usize,
1311 upvalues: Rc::new(upvalues),
1312 };
1313 self.set_register(dest, closure)?;
1314 }
1315
1316 Instruction::LoadUpvalue(dest, upvalue_idx) => {
1317 let frame = self
1318 .call_stack
1319 .last()
1320 .ok_or_else(|| LustError::RuntimeError {
1321 message: "Empty call stack".to_string(),
1322 })?;
1323 if (upvalue_idx as usize) < frame.upvalues.len() {
1324 let value = frame.upvalues[upvalue_idx as usize].clone();
1325 self.set_register(dest, value)?;
1326 } else {
1327 return Err(LustError::RuntimeError {
1328 message: format!(
1329 "Upvalue index {} out of bounds (have {} upvalues)",
1330 upvalue_idx,
1331 frame.upvalues.len()
1332 ),
1333 });
1334 }
1335 }
1336
1337 Instruction::StoreUpvalue(upvalue_idx, src) => {
1338 let value = self.get_register(src)?.clone();
1339 let frame =
1340 self.call_stack
1341 .last_mut()
1342 .ok_or_else(|| LustError::RuntimeError {
1343 message: "Empty call stack".to_string(),
1344 })?;
1345 if (upvalue_idx as usize) < frame.upvalues.len() {
1346 frame.upvalues[upvalue_idx as usize] = value;
1347 } else {
1348 return Err(LustError::RuntimeError {
1349 message: format!(
1350 "Upvalue index {} out of bounds (have {} upvalues)",
1351 upvalue_idx,
1352 frame.upvalues.len()
1353 ),
1354 });
1355 }
1356 }
1357
1358 Instruction::SetIndex(collection_reg, index_reg, value_reg) => {
1359 let collection = self.get_register(collection_reg)?.clone();
1360 let index = self.get_register(index_reg)?.clone();
1361 let value = self.get_register(value_reg)?.clone();
1362 if let Some(map_val) = Self::lua_table_map(&collection) {
1363 if let Value::Map(map) = map_val {
1364 let key = self.make_hash_key(&Self::lua_table_key_value(&index))?;
1365 if self.budgets.mem_budget_enabled() && !map.borrow().contains_key(&key)
1366 {
1367 self.budgets.charge_map_entry_estimate()?;
1368 }
1369 map.borrow_mut().insert(key, value);
1370 } else {
1371 return Err(LustError::RuntimeError {
1372 message: format!("Cannot index {:?}", collection.type_of()),
1373 });
1374 }
1375 } else {
1376 match collection {
1377 Value::Array(arr) => {
1378 let idx = index.as_int().ok_or_else(|| LustError::RuntimeError {
1379 message: "Array index must be an integer".to_string(),
1380 })?;
1381 let mut borrowed = arr.borrow_mut();
1382 if idx < 0 || idx as usize >= borrowed.len() {
1383 return Err(LustError::RuntimeError {
1384 message: format!(
1385 "Array index {} out of bounds (length: {})",
1386 idx,
1387 borrowed.len()
1388 ),
1389 });
1390 }
1391
1392 borrowed[idx as usize] = value;
1393 }
1394
1395 Value::Map(map) => {
1396 let key = self.make_hash_key(&index)?;
1397 if self.budgets.mem_budget_enabled()
1398 && !map.borrow().contains_key(&key)
1399 {
1400 self.budgets.charge_map_entry_estimate()?;
1401 }
1402 map.borrow_mut().insert(key, value);
1403 }
1404
1405 _ => {
1406 return Err(LustError::RuntimeError {
1407 message: format!("Cannot index {:?}", collection.type_of()),
1408 })
1409 }
1410 }
1411 }
1412 }
1413
1414 Instruction::TypeIs(dest, value_reg, type_name_idx) => {
1415 let value = self.get_register(value_reg)?.clone();
1416 let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1417 let type_name = func.chunk.constants[type_name_idx as usize]
1418 .as_string()
1419 .ok_or_else(|| LustError::RuntimeError {
1420 message: "Type name must be a string".to_string(),
1421 })?
1422 .to_string();
1423 let matches = self.value_is_type(&value, &type_name);
1424 self.set_register(dest, Value::Bool(matches))?;
1425 }
1426 }
1427
1428 if self.jit.enabled {
1429 if let Some(recorder) = &mut self.trace_recorder {
1430 if recorder.is_recording() {
1431 if self.skip_next_trace_record {
1432 self.skip_next_trace_record = false;
1433 } else {
1434 let function = &self.functions[func_idx];
1435 let registers_opt =
1436 if let Some(frame) = self.call_stack.get(executing_frame_index) {
1437 Some(&frame.registers)
1438 } else if executing_frame_index > 0 {
1439 self.call_stack
1440 .get(executing_frame_index - 1)
1441 .map(|frame| &frame.registers)
1442 } else {
1443 None
1444 };
1445 if let Some(registers) = registers_opt {
1446 if let Err(e) = recorder.record_instruction(
1447 instruction,
1448 ip_before_execution,
1449 registers,
1450 function,
1451 func_idx,
1452 &self.functions,
1453 ) {
1454 crate::jit::log(|| format!("⚠️ JIT: {}", e));
1455 self.trace_recorder = None;
1456 }
1457 }
1458 }
1459 }
1460 }
1461 }
1462 }
1463 }
1464
1465 pub(super) fn binary_op<F>(
1466 &mut self,
1467 dest: Register,
1468 lhs: Register,
1469 rhs: Register,
1470 op: F,
1471 ) -> Result<()>
1472 where
1473 F: FnOnce(&Value, &Value) -> Result<Value>,
1474 {
1475 let left = self.get_register(lhs)?;
1476 let right = self.get_register(rhs)?;
1477 let result = op(left, right)?;
1478 self.set_register(dest, result)
1479 }
1480
1481 pub(super) fn comparison_op<F>(
1482 &mut self,
1483 dest: Register,
1484 lhs: Register,
1485 rhs: Register,
1486 op: F,
1487 ) -> Result<()>
1488 where
1489 F: FnOnce(LustFloat, LustFloat) -> bool,
1490 {
1491 let left = self.get_register(lhs)?;
1492 let right = self.get_register(rhs)?;
1493 let result = match (left, right) {
1494 (Value::Int(a), Value::Int(b)) => op(float_from_int(*a), float_from_int(*b)),
1495 (Value::Float(a), Value::Float(b)) => op(*a, *b),
1496 (Value::Int(a), Value::Float(b)) => op(float_from_int(*a), *b),
1497 (Value::Float(a), Value::Int(b)) => op(*a, float_from_int(*b)),
1498 _ => {
1499 return Err(LustError::RuntimeError {
1500 message: format!("Cannot compare {:?} and {:?}", left, right),
1501 })
1502 }
1503 };
1504 self.set_register(dest, Value::Bool(result))
1505 }
1506
1507 pub(super) fn value_is_type(&self, value: &Value, type_name: &str) -> bool {
1508 if let Some(matches) = self.match_function_type(value, type_name) {
1509 return matches;
1510 }
1511
1512 let value_type_name = match value {
1513 Value::Int(_) => "int",
1514 Value::Float(_) => "float",
1515 Value::String(_) => "string",
1516 Value::Bool(_) => "bool",
1517 Value::Nil => "nil",
1518 Value::Array(_) => "Array",
1519 Value::Tuple(_) => "Tuple",
1520 Value::Map(_) => "Map",
1521 Value::Struct { name, .. } => name.as_str(),
1522 Value::WeakStruct(weak) => weak.struct_name(),
1523 Value::Enum { enum_name, .. } => enum_name.as_str(),
1524 Value::Function(_) | Value::NativeFunction(_) | Value::Closure { .. } => "function",
1525 Value::Iterator(_) => "Iterator",
1526 Value::Task(_) => "task",
1527 };
1528 if value_type_name == type_name {
1529 return true;
1530 }
1531
1532 if type_name.starts_with("Array") && matches!(value, Value::Array(_)) {
1533 return true;
1534 }
1535
1536 if type_name.starts_with("Map") && matches!(value, Value::Map(_)) {
1537 return true;
1538 }
1539
1540 if type_name.starts_with("Tuple") && matches!(value, Value::Tuple(_)) {
1541 return true;
1542 }
1543
1544 if type_name == "Option"
1545 && matches!(value, Value::Enum { enum_name, .. } if enum_name == "Option")
1546 {
1547 return true;
1548 }
1549
1550 if type_name == "Result"
1551 && matches!(value, Value::Enum { enum_name, .. } if enum_name == "Result")
1552 {
1553 return true;
1554 }
1555
1556 if type_name == "unknown" {
1557 return true;
1558 }
1559
1560 if let Some(_) = self
1561 .trait_impls
1562 .get(&(value_type_name.to_string(), type_name.to_string()))
1563 {
1564 return true;
1565 }
1566
1567 false
1568 }
1569
1570 fn value_trait_name(&self, value: &Value) -> String {
1571 match value {
1572 Value::Int(_) => "int".to_string(),
1573 Value::Float(_) => "float".to_string(),
1574 Value::String(_) => "string".to_string(),
1575 Value::Bool(_) => "bool".to_string(),
1576 Value::Nil => "nil".to_string(),
1577 Value::Array(_) => "Array".to_string(),
1578 Value::Tuple(_) => "Tuple".to_string(),
1579 Value::Map(_) => "Map".to_string(),
1580 Value::Struct { name, .. } => name.clone(),
1581 Value::WeakStruct(weak) => weak.struct_name().to_string(),
1582 Value::Enum { enum_name, .. } => enum_name.clone(),
1583 Value::Function(_) | Value::NativeFunction(_) | Value::Closure { .. } => {
1584 "function".to_string()
1585 }
1586 Value::Iterator(_) => "Iterator".to_string(),
1587 Value::Task(_) => "task".to_string(),
1588 }
1589 }
1590
1591 fn invoke_hashkey(&mut self, value: &Value, type_name: &str) -> Result<Value> {
1592 let mut candidates = vec![format!("{}:{}", type_name, HASH_KEY_METHOD)];
1593 if let Some(last) = type_name.rsplit('.').next() {
1594 if last != type_name {
1595 candidates.push(format!("{}:{}", last, HASH_KEY_METHOD));
1596 }
1597 }
1598
1599 for candidate in candidates {
1600 if let Some(idx) = self.functions.iter().position(|f| f.name == candidate) {
1601 return self.call_value(&Value::Function(idx), vec![value.clone()]);
1602 }
1603 }
1604
1605 Err(LustError::RuntimeError {
1606 message: format!(
1607 "HashKey trait declared but method '{}' not found for type '{}'",
1608 HASH_KEY_METHOD, type_name
1609 ),
1610 })
1611 }
1612
1613 pub(super) fn make_hash_key(&mut self, value: &Value) -> Result<ValueKey> {
1614 let type_name = self.value_trait_name(value);
1615 if self.type_has_hashkey(&type_name) {
1616 let hashed = self.invoke_hashkey(value, &type_name)?;
1617 Ok(ValueKey::with_hashed(value.clone(), hashed))
1618 } else {
1619 Ok(ValueKey::from_value(value))
1620 }
1621 }
1622
1623 fn match_function_type(&self, value: &Value, type_name: &str) -> Option<bool> {
1624 let wants_signature = type_name.starts_with("function(");
1625 let wants_generic = type_name == "function";
1626 if !wants_signature && !wants_generic {
1627 return None;
1628 }
1629
1630 let matches = match value {
1631 Value::Function(idx) => self.function_signature_matches(*idx, type_name),
1632 Value::Closure { function_idx, .. } => {
1633 self.function_signature_matches(*function_idx, type_name)
1634 }
1635 Value::NativeFunction(_) => wants_generic,
1636 _ => false,
1637 };
1638 Some(matches)
1639 }
1640
1641 fn function_signature_matches(&self, func_idx: usize, type_name: &str) -> bool {
1642 if type_name == "function" {
1643 return true;
1644 }
1645
1646 self.functions
1647 .get(func_idx)
1648 .and_then(|func| func.signature.as_ref())
1649 .map(|signature| signature.to_string() == type_name)
1650 .unwrap_or(false)
1651 }
1652
1653 pub(super) fn get_register(&self, reg: Register) -> Result<&Value> {
1654 let frame = self
1655 .call_stack
1656 .last()
1657 .ok_or_else(|| LustError::RuntimeError {
1658 message: "Empty call stack".to_string(),
1659 })?;
1660 Ok(&frame.registers[reg as usize])
1661 }
1662
1663 pub(super) fn set_register(&mut self, reg: Register, value: Value) -> Result<()> {
1664 self.observe_value(&value);
1665 let frame = self
1666 .call_stack
1667 .last_mut()
1668 .ok_or_else(|| LustError::RuntimeError {
1669 message: "Empty call stack".to_string(),
1670 })?;
1671 frame.registers[reg as usize] = value;
1672 self.maybe_collect_cycles();
1673 Ok(())
1674 }
1675
1676 pub(super) fn handle_native_call_outcome(
1677 &mut self,
1678 dest: Register,
1679 outcome: NativeCallResult,
1680 ) -> Result<()> {
1681 #[cfg(feature = "std")]
1682 if std::env::var_os("LUST_LUA_SOCKET_TRACE").is_some() {
1683 if let NativeCallResult::Return(value) = &outcome {
1684 if let Value::Array(arr) = value {
1685 let borrowed = arr.borrow();
1686 let interesting = borrowed.len() > 1
1687 && matches!(
1688 borrowed.get(0),
1689 Some(Value::Enum { enum_name, variant, .. })
1690 if enum_name == "LuaValue" && variant == "Nil"
1691 );
1692 if interesting {
1693 let func_name = self
1694 .call_stack
1695 .last()
1696 .and_then(|frame| self.functions.get(frame.function_idx))
1697 .map(|f| f.name.as_str())
1698 .unwrap_or("<unknown>");
1699 eprintln!(
1700 "[lua-socket] native return in {} dest=R{} len={} value={}",
1701 func_name,
1702 dest,
1703 borrowed.len(),
1704 value
1705 );
1706 }
1707 }
1708 }
1709 }
1710 match outcome {
1711 NativeCallResult::Return(value) => self.set_register(dest, value),
1712 NativeCallResult::Yield(value) => {
1713 if self.current_task.is_some() {
1714 self.set_register(dest, Value::Nil)?;
1715 self.pending_task_signal = Some(TaskSignal::Yield { dest, value });
1716 Ok(())
1717 } else {
1718 Err(LustError::RuntimeError {
1719 message: "task.yield() can only be used inside a task".to_string(),
1720 })
1721 }
1722 }
1723
1724 NativeCallResult::Stop(value) => {
1725 if self.current_task.is_some() {
1726 self.set_register(dest, Value::Nil)?;
1727 self.pending_task_signal = Some(TaskSignal::Stop { value });
1728 Ok(())
1729 } else {
1730 Err(LustError::RuntimeError {
1731 message: "task.stop() can only be used inside a task".to_string(),
1732 })
1733 }
1734 }
1735 }
1736 }
1737
1738 pub fn value_to_string_for_concat(&mut self, value: &Value) -> Result<Rc<String>> {
1739 match value {
1740 Value::String(s) => Ok(s.clone()),
1741 Value::Struct { name, .. } => self.invoke_tostring(value, name),
1742 Value::Enum { enum_name, .. } => self.invoke_tostring(value, enum_name),
1743 _ => Ok(Rc::new(value.to_string())),
1744 }
1745 }
1746
1747 #[inline(never)]
1748 pub fn call_value(&mut self, func: &Value, args: Vec<Value>) -> Result<Value> {
1749 let mut args = args;
1753 let maybe_lua_call = {
1754 let mut current = func;
1755 let mut receiver_wrapped = func.clone();
1756
1757 if let Value::Struct { name, .. } = func {
1758 if name == "LuaTable" {
1759 receiver_wrapped = Value::enum_variant("LuaValue", "Table", vec![func.clone()]);
1760 } else if name == "LuaUserdata" {
1761 receiver_wrapped =
1762 Value::enum_variant("LuaValue", "Userdata", vec![func.clone()]);
1763 }
1764 }
1765
1766 if let Value::Enum {
1767 enum_name,
1768 variant,
1769 values,
1770 } = func
1771 {
1772 if enum_name == "LuaValue" && (variant == "Table" || variant == "Userdata") {
1773 if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1774 current = inner;
1775 }
1776 }
1777 }
1778
1779 if let Value::Struct { name, .. } = current {
1780 if name == "LuaTable" || name == "LuaUserdata" {
1781 if let Some(Value::Map(meta_rc)) = current.struct_get_field("metamethods") {
1782 meta_rc
1783 .borrow()
1784 .get(&ValueKey::string("__call".to_string()))
1785 .cloned()
1786 .map(|callable| (callable, receiver_wrapped))
1787 } else {
1788 None
1789 }
1790 } else {
1791 None
1792 }
1793 } else {
1794 None
1795 }
1796 };
1797
1798 if let Some((callable, receiver)) = maybe_lua_call {
1799 let mut call_args = Vec::with_capacity(args.len() + 1);
1801 call_args.push(receiver);
1802 call_args.append(&mut args);
1803 return self.call_value(&callable, call_args);
1804 } else {
1805 }
1811
1812 match func {
1813 #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
1814 Value::Enum {
1815 enum_name,
1816 variant,
1817 values,
1818 } if enum_name == "LuaValue" && variant == "Function" => {
1819 let handle = values
1820 .as_ref()
1821 .and_then(|vals| vals.get(0))
1822 .and_then(|v| v.struct_get_field("handle"))
1823 .and_then(|v| v.as_int())
1824 .map(|i| i as usize)
1825 .ok_or_else(|| LustError::RuntimeError {
1826 message: "LuaValue function missing handle".to_string(),
1827 })?;
1828 let inner = crate::lua_compat::lookup_lust_function(handle).ok_or_else(|| {
1829 LustError::RuntimeError {
1830 message: format!(
1831 "LuaValue function handle {} was not registered with VM",
1832 handle
1833 ),
1834 }
1835 })?;
1836 return self.call_value(&inner, args);
1837 }
1838 Value::Function(func_idx) => {
1839 let saved_pending_return_value = self.pending_return_value.clone();
1840 let saved_pending_return_dest = self.pending_return_dest;
1841 let saved_pending_task_signal = self.pending_task_signal.clone();
1842 let saved_last_task_signal = self.last_task_signal.clone();
1843
1844 let mut frame = CallFrame {
1845 function_idx: *func_idx,
1846 ip: 0,
1847 registers: array::from_fn(|_| Value::Nil),
1848 base_register: 0,
1849 return_dest: None,
1850 upvalues: Vec::new(),
1851 };
1852 for (i, arg) in args.into_iter().enumerate() {
1853 frame.registers[i] = arg;
1854 }
1855
1856 let stack_depth_before = self.call_stack.len();
1857 self.call_stack.push(frame);
1858 let previous_target = self.call_until_depth;
1859 self.call_until_depth = Some(stack_depth_before);
1860 let run_result = self.run();
1861 self.call_until_depth = previous_target;
1862 match run_result {
1863 Ok(value) => Ok(value),
1864 Err(err) => {
1865 let annotated = self.annotate_runtime_error(err);
1866 while self.call_stack.len() > stack_depth_before {
1867 self.call_stack.pop();
1868 }
1869 self.pending_return_value = saved_pending_return_value;
1870 self.pending_return_dest = saved_pending_return_dest;
1871 self.pending_task_signal = saved_pending_task_signal;
1872 self.last_task_signal = saved_last_task_signal;
1873 Err(annotated)
1874 }
1875 }
1876 }
1877
1878 Value::Closure {
1879 function_idx: func_idx,
1880 upvalues,
1881 } => {
1882 let saved_pending_return_value = self.pending_return_value.clone();
1883 let saved_pending_return_dest = self.pending_return_dest;
1884 let saved_pending_task_signal = self.pending_task_signal.clone();
1885 let saved_last_task_signal = self.last_task_signal.clone();
1886
1887 let upvalue_values: Vec<Value> = upvalues.iter().map(|uv| uv.get()).collect();
1888 let mut frame = CallFrame {
1889 function_idx: *func_idx,
1890 ip: 0,
1891 registers: array::from_fn(|_| Value::Nil),
1892 base_register: 0,
1893 return_dest: None,
1894 upvalues: upvalue_values,
1895 };
1896 for (i, arg) in args.into_iter().enumerate() {
1897 frame.registers[i] = arg;
1898 }
1899
1900 let stack_depth_before = self.call_stack.len();
1901 self.call_stack.push(frame);
1902 let previous_target = self.call_until_depth;
1903 self.call_until_depth = Some(stack_depth_before);
1904 let run_result = self.run();
1905 self.call_until_depth = previous_target;
1906 match run_result {
1907 Ok(value) => Ok(value),
1908 Err(err) => {
1909 let annotated = self.annotate_runtime_error(err);
1910 while self.call_stack.len() > stack_depth_before {
1911 self.call_stack.pop();
1912 }
1913 self.pending_return_value = saved_pending_return_value;
1914 self.pending_return_dest = saved_pending_return_dest;
1915 self.pending_task_signal = saved_pending_task_signal;
1916 self.last_task_signal = saved_last_task_signal;
1917 Err(annotated)
1918 }
1919 }
1920 }
1921
1922 Value::NativeFunction(native_fn) => {
1923 self.push_current_vm();
1924 let outcome = native_fn(&args);
1925 self.pop_current_vm();
1926 let outcome = outcome.map_err(|e| LustError::RuntimeError { message: e })?;
1927 match outcome {
1928 NativeCallResult::Return(value) => Ok(value),
1929 NativeCallResult::Yield(_) | NativeCallResult::Stop(_) => {
1930 Err(LustError::RuntimeError {
1931 message: "Yielding or stopping is not allowed from this context"
1932 .to_string(),
1933 })
1934 }
1935 }
1936 }
1937
1938 _ => Err(LustError::RuntimeError {
1939 message: format!("Cannot call non-function value: {:?}", func),
1940 }),
1941 }
1942 }
1943}