Skip to main content

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