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