lust/vm/
execution.rs

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                        // Capture RSP before and after to detect stack leaks
167                        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                            // Specialize loop-invariant values at trace entry
385                            {
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                    // if let Value::Enum { enum_name, variant, .. } = &func_value {
665                    //     if enum_name == "LuaValue" && variant == "Table" {
666                    //         eprintln!("DEBUG: Instruction::Call with LuaValue.Table");
667                    //     }
668                    // }
669
670                    // Check if this is a table/userdata with __call metamethod (Lua compat)
671                    let needs_call_value = {
672                        let mut check_value = &func_value;
673                        // Unwrap LuaValue enum if needed
674                        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                        // Check if it's a LuaTable/LuaUserdata struct with metamethods
682                        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                        // eprintln!("DEBUG Instruction::Call: Delegating to call_value for table/userdata");
692                        // Delegate to call_value which handles __call metamethods
693                        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                        // Check what type we're actually dealing with
702                        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        // Lua compatibility: honor __call metamethod on Lua tables/userdata.
1740        // Lua semantics: if value has metatable.__call, calling it invokes that function with the
1741        // receiver as the first argument.
1742        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            // eprintln!("DEBUG: __call metamethod found, invoking with receiver");
1790            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            // if let Value::Struct { name, .. } = func {
1796            //     if name == "LuaTable" || name == "LuaUserdata" {
1797            //         eprintln!("DEBUG: Calling LuaTable/Userdata but no __call found in metamethods");
1798            //     }
1799            // }
1800        }
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}