Skip to main content

lust/vm/
execution.rs

1use super::*;
2use crate::bytecode::ValueKey;
3use core::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 func_value = self.get_register(func_reg)?.clone();
672                    #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
673                    let mut func_value = func_value;
674                    // if let Value::Enum { enum_name, variant, .. } = &func_value {
675                    //     if enum_name == "LuaValue" && variant == "Table" {
676                    //         eprintln!("DEBUG: Instruction::Call with LuaValue.Table");
677                    //     }
678                    // }
679
680                    // Check if this is a table/userdata with __call metamethod (Lua compat)
681                    let needs_call_value = {
682                        let mut check_value = &func_value;
683                        // Unwrap LuaValue enum if needed
684                        if let Value::Enum { enum_name, variant, values } = &func_value {
685                            if enum_name == "LuaValue" && (variant == "Table" || variant == "Userdata") {
686                                if let Some(inner) = values.as_ref().and_then(|v| v.get(0)) {
687                                    check_value = inner;
688                                }
689                            }
690                        }
691                        // Check if it's a LuaTable/LuaUserdata struct with metamethods
692                        if let Value::Struct { name, .. } = check_value {
693                            (name == "LuaTable" || name == "LuaUserdata") &&
694                            check_value.struct_get_field("metamethods").is_some()
695                        } else {
696                            false
697                        }
698                    };
699
700                    if needs_call_value {
701                        // eprintln!("DEBUG Instruction::Call: Delegating to call_value for table/userdata");
702                        // Delegate to call_value which handles __call metamethods
703                        let mut args = Vec::new();
704                        for i in 0..arg_count {
705                            args.push(self.get_register(first_arg + i)?.clone());
706                        }
707                        let result = self.call_value(&func_value, args)?;
708                        self.set_register(dest_reg, result)?;
709                        continue;
710                    } else {
711                        // Check what type we're actually dealing with
712                        if let Value::Enum { enum_name, variant, .. } = &func_value {
713                            if enum_name == "LuaValue" && (variant == "Table" || variant == "Userdata") {
714                                #[cfg(feature = "std")]
715                                eprintln!("DEBUG Instruction::Call: Have LuaValue.{} but needs_call_value=false", variant);
716                            }
717                        }
718                    }
719
720                    #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
721                    loop {
722                        let handle = match &func_value {
723                            Value::Enum {
724                                enum_name,
725                                variant,
726                                values,
727                            } if enum_name == "LuaValue" && variant == "Function" => values
728                                .as_ref()
729                                .and_then(|vals| vals.get(0))
730                                .and_then(|v| v.struct_get_field("handle"))
731                                .and_then(|v| v.as_int())
732                                .map(|i| i as usize),
733                            _ => None,
734                        };
735                        let Some(handle) = handle else { break };
736                        let inner = crate::lua_compat::lookup_lust_function(handle).ok_or_else(|| {
737                            LustError::RuntimeError {
738                                message: format!(
739                                    "LuaValue function handle {} was not registered with VM",
740                                    handle
741                                ),
742                            }
743                        })?;
744                        func_value = inner;
745                    }
746                    match func_value {
747                        Value::Function(func_idx) => {
748                            let mut args = Vec::new();
749                            for i in 0..arg_count {
750                                args.push(self.get_register(first_arg + i)?.clone());
751                            }
752
753                            let register_count = self.functions[func_idx].register_count;
754                            let mut frame = CallFrame::new(func_idx, Some(dest_reg), register_count);
755                            for (i, arg) in args.into_iter().enumerate() {
756                                frame.registers[i] = arg;
757                            }
758
759                            self.call_stack.push(frame);
760                        }
761
762                        Value::Closure {
763                            function_idx: func_idx,
764                            upvalues,
765                        } => {
766                            let mut args = Vec::new();
767                            for i in 0..arg_count {
768                                args.push(self.get_register(first_arg + i)?.clone());
769                            }
770
771                            let upvalue_values: Vec<Value> =
772                                upvalues.iter().map(|uv| uv.get()).collect();
773                            let register_count = self.functions[func_idx].register_count;
774                            let mut frame = CallFrame::new(func_idx, Some(dest_reg), register_count);
775                            frame.upvalues = upvalue_values;
776                            for (i, arg) in args.into_iter().enumerate() {
777                                frame.registers[i] = arg;
778                            }
779
780                            self.call_stack.push(frame);
781                        }
782
783                        Value::NativeFunction(native_fn) => {
784                            let mut args = Vec::new();
785                            for i in 0..arg_count {
786                                args.push(self.get_register(first_arg + i)?.clone());
787                            }
788
789                            self.push_current_vm();
790                            let outcome = native_fn(&args);
791                            self.pop_current_vm();
792                            let outcome =
793                                outcome.map_err(|e| LustError::RuntimeError { message: e })?;
794                            self.handle_native_call_outcome(dest_reg, outcome)?;
795                        }
796
797                        _ => {
798                            return Err(LustError::RuntimeError {
799                                message: format!(
800                                    "Cannot call non-function value: {:?}",
801                                    func_value
802                                ),
803                            })
804                        }
805                    }
806                }
807
808                Instruction::Return(value_reg) => {
809                    let return_value = if value_reg == 255 {
810                        Value::Nil
811                    } else {
812                        self.get_register(value_reg)?.clone()
813                    };
814                    let return_dest = self.call_stack.last().unwrap().return_dest;
815                    self.call_stack.pop();
816                    if self.call_stack.is_empty() {
817                        return Ok(return_value);
818                    }
819
820                    self.pending_return_value = Some(return_value);
821                    self.pending_return_dest = return_dest;
822                }
823
824                Instruction::NewArray(dest, first_elem, count) => {
825                    let element_count = count as usize;
826                    self.budgets.charge_value_vec(element_count)?;
827                    let mut elements = Vec::with_capacity(element_count);
828                    for i in 0..count {
829                        elements.push(self.get_register(first_elem + i)?.clone());
830                    }
831
832                    self.set_register(dest, Value::array(elements))?;
833                }
834
835                Instruction::TupleNew(dest, first_elem, count) => {
836                    let mut parts = Vec::with_capacity(count as usize);
837                    let mut total_elements: usize = 0;
838                    for offset in 0..(count as usize) {
839                        let value = self.get_register(first_elem + offset as u8)?.clone();
840                        total_elements = total_elements.saturating_add(match &value {
841                            Value::Tuple(existing) => existing.len(),
842                            _ => 1,
843                        });
844                        parts.push(value);
845                    }
846
847                    self.budgets.charge_value_vec(total_elements)?;
848                    let mut elements = Vec::with_capacity(total_elements);
849                    for value in parts {
850                        if let Value::Tuple(existing) = value {
851                            elements.extend(existing.iter().cloned());
852                        } else {
853                            elements.push(value);
854                        }
855                    }
856
857                    self.set_register(dest, Value::tuple(elements))?;
858                }
859
860                Instruction::TupleGet(dest, tuple_reg, index) => {
861                    let tuple_value = self.get_register(tuple_reg)?.clone();
862                    if let Value::Tuple(values) = tuple_value {
863                        let idx = index as usize;
864                        if idx >= values.len() {
865                            return Err(LustError::RuntimeError {
866                                message: format!(
867                                    "Tuple index {} out of bounds (len {})",
868                                    idx,
869                                    values.len()
870                                ),
871                            });
872                        }
873
874                        let value = values[idx].clone();
875                        self.set_register(dest, value)?;
876                    } else {
877                        return Err(LustError::RuntimeError {
878                            message: "Attempted to destructure non-tuple value".to_string(),
879                        });
880                    }
881                }
882
883                Instruction::NewMap(dest) => {
884                    self.set_register(dest, self.new_map_value())?;
885                }
886
887                Instruction::NewStruct(
888                    dest,
889                    name_idx,
890                    first_field_name_idx,
891                    first_field,
892                    field_count,
893                ) => {
894                    self.budgets.charge_value_vec(field_count as usize)?;
895                    let func = &self.functions[self.call_stack.last().unwrap().function_idx];
896                    let struct_name = func.chunk.constants[name_idx as usize]
897                        .as_string()
898                        .ok_or_else(|| LustError::RuntimeError {
899                            message: "Struct name must be a string".to_string(),
900                        })?
901                        .to_string();
902                    let mut fields = Vec::with_capacity(field_count as usize);
903                    for i in 0..field_count {
904                        let field_name = func.chunk.constants
905                            [(first_field_name_idx + i as u16) as usize]
906                            .as_string_rc()
907                            .ok_or_else(|| LustError::RuntimeError {
908                                message: "Field name must be a string".to_string(),
909                            })?;
910                        let value = self.get_register(first_field + i)?.clone();
911                        fields.push((field_name, value));
912                    }
913
914                    let struct_value = self.instantiate_struct(&struct_name, fields)?;
915                    self.set_register(dest, struct_value)?;
916                }
917
918                Instruction::NewEnumUnit(dest, enum_name_idx, variant_idx) => {
919                    let func = &self.functions[self.call_stack.last().unwrap().function_idx];
920                    let enum_name = func.chunk.constants[enum_name_idx as usize]
921                        .as_string()
922                        .ok_or_else(|| LustError::RuntimeError {
923                            message: "Enum name must be a string".to_string(),
924                        })?
925                        .to_string();
926                    let variant_name = func.chunk.constants[variant_idx as usize]
927                        .as_string()
928                        .ok_or_else(|| LustError::RuntimeError {
929                            message: "Variant name must be a string".to_string(),
930                        })?
931                        .to_string();
932                    self.set_register(dest, Value::enum_unit(enum_name, variant_name))?;
933                }
934
935                Instruction::NewEnumVariant(
936                    dest,
937                    enum_name_idx,
938                    variant_idx,
939                    first_value,
940                    value_count,
941                ) => {
942                    self.budgets.charge_value_vec(value_count as usize)?;
943                    let func = &self.functions[self.call_stack.last().unwrap().function_idx];
944                    let enum_name = func.chunk.constants[enum_name_idx as usize]
945                        .as_string()
946                        .ok_or_else(|| LustError::RuntimeError {
947                            message: "Enum name must be a string".to_string(),
948                        })?
949                        .to_string();
950                    let variant_name = func.chunk.constants[variant_idx as usize]
951                        .as_string()
952                        .ok_or_else(|| LustError::RuntimeError {
953                            message: "Variant name must be a string".to_string(),
954                        })?
955                        .to_string();
956                    let mut values = Vec::with_capacity(value_count as usize);
957                    for i in 0..value_count {
958                        values.push(self.get_register(first_value + i)?.clone());
959                    }
960
961                    self.set_register(dest, Value::enum_variant(enum_name, variant_name, values))?;
962                }
963
964                Instruction::IsEnumVariant(dest, value_reg, enum_name_idx, variant_idx) => {
965                    let value = self.get_register(value_reg)?;
966                    let func = &self.functions[self.call_stack.last().unwrap().function_idx];
967                    let enum_name = func.chunk.constants[enum_name_idx as usize]
968                        .as_string()
969                        .ok_or_else(|| LustError::RuntimeError {
970                            message: "Enum name must be a string".to_string(),
971                        })?;
972                    let variant_name = func.chunk.constants[variant_idx as usize]
973                        .as_string()
974                        .ok_or_else(|| LustError::RuntimeError {
975                            message: "Variant name must be a string".to_string(),
976                        })?;
977                    let is_variant = value.is_enum_variant(enum_name, variant_name);
978                    self.set_register(dest, Value::Bool(is_variant))?;
979                }
980
981                Instruction::GetEnumValue(dest, enum_reg, index) => {
982                    let enum_value = self.get_register(enum_reg)?;
983                    if let Some((_, _, Some(values))) = enum_value.as_enum() {
984                        if (index as usize) < values.len() {
985                            self.set_register(dest, values[index as usize].clone())?;
986                        } else {
987                            return Err(LustError::RuntimeError {
988                                message: format!(
989                                    "Enum value index {} out of bounds (has {} values)",
990                                    index,
991                                    values.len()
992                                ),
993                            });
994                        }
995                    } else {
996                        return Err(LustError::RuntimeError {
997                            message: "GetEnumValue requires an enum variant with values"
998                                .to_string(),
999                        });
1000                    }
1001                }
1002
1003                Instruction::GetField(dest, obj, field_idx) => {
1004                    let object = self.get_register(obj)?;
1005                    let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1006                    let field_name = func.chunk.constants[field_idx as usize]
1007                        .as_string_rc()
1008                        .ok_or_else(|| LustError::RuntimeError {
1009                            message: "Field name must be a string".to_string(),
1010                        })?;
1011                    let value = if let Some(map_val) = Self::lua_table_map(object) {
1012                        if let Value::Map(map) = map_val {
1013                            let raw_key_value = Value::String(field_name.clone());
1014                            let key = self.make_hash_key(&Self::lua_table_key_value(&raw_key_value))?;
1015                            let borrowed = map.borrow();
1016                            borrowed.get(&key).cloned().unwrap_or(Value::Nil)
1017                        } else {
1018                            Value::Nil
1019                        }
1020                    } else {
1021                        match object {
1022                            Value::Struct { .. } => object
1023                                .struct_get_field_rc(&field_name)
1024                                .unwrap_or(Value::Nil),
1025                            Value::Map(map) => {
1026                                let key = ValueKey::from(field_name.clone());
1027                                map.borrow().get(&key).cloned().unwrap_or(Value::Nil)
1028                            }
1029
1030                            _ => {
1031                                return Err(LustError::RuntimeError {
1032                                    message: format!(
1033                                        "Cannot get field '{}' from {:?}",
1034                                        field_name.as_str(),
1035                                        object
1036                                    ),
1037                                })
1038                            }
1039                        }
1040                    };
1041                    self.set_register(dest, value)?;
1042                }
1043
1044                Instruction::SetField(obj_reg, field_idx, value_reg) => {
1045                    let object = self.get_register(obj_reg)?.clone();
1046                    let value = self.get_register(value_reg)?.clone();
1047                    let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1048                    let field_name = func.chunk.constants[field_idx as usize]
1049                        .as_string_rc()
1050                        .ok_or_else(|| LustError::RuntimeError {
1051                            message: "Field name must be a string".to_string(),
1052                        })?;
1053                    let mut invalidate_key: Option<usize> = None;
1054                    if let Some(map_val) = Self::lua_table_map(&object) {
1055                        if let Value::Map(map) = map_val {
1056                            let raw_key_value = Value::String(field_name.clone());
1057                            let key = self.make_hash_key(&Self::lua_table_key_value(&raw_key_value))?;
1058                            if self.budgets.mem_budget_enabled() && !map.borrow().contains_key(&key)
1059                            {
1060                                self.budgets.charge_map_entry_estimate()?;
1061                            }
1062                            map.borrow_mut().insert(key, value);
1063                        } else {
1064                            return Err(LustError::RuntimeError {
1065                                message: format!(
1066                                    "Cannot set field '{}' on {:?}",
1067                                    field_name.as_str(),
1068                                    object
1069                                ),
1070                            });
1071                        }
1072                    } else {
1073                        match &object {
1074                            Value::Struct { .. } => {
1075                                invalidate_key = Self::struct_cache_key(&object);
1076                                object
1077                                    .struct_set_field_rc(&field_name, value)
1078                                    .map_err(|message| LustError::RuntimeError { message })?;
1079                            }
1080
1081                            Value::Map(map) => {
1082                                let key = ValueKey::from(field_name.clone());
1083                                if self.budgets.mem_budget_enabled()
1084                                    && !map.borrow().contains_key(&key)
1085                                {
1086                                    self.budgets.charge_map_entry_estimate()?;
1087                                }
1088                                map.borrow_mut().insert(key, value);
1089                            }
1090
1091                            _ => {
1092                                return Err(LustError::RuntimeError {
1093                                    message: format!(
1094                                        "Cannot set field '{}' on {:?}",
1095                                        field_name.as_str(),
1096                                        object
1097                                    ),
1098                                })
1099                            }
1100                        }
1101                    }
1102
1103                    if let Some(key) = invalidate_key {
1104                        self.struct_tostring_cache.remove(&key);
1105                    }
1106                }
1107
1108                Instruction::Concat(dest, lhs, rhs) => {
1109                    let (left, right) = {
1110                        let frame =
1111                            self.call_stack
1112                                .last_mut()
1113                                .ok_or_else(|| LustError::RuntimeError {
1114                                    message: "Empty call stack".to_string(),
1115                                })?;
1116                        let left = frame.registers[lhs as usize].clone();
1117                        let right = frame.registers[rhs as usize].clone();
1118                        (left, right)
1119                    };
1120                    let left_str = self.value_to_string_for_concat(&left)?;
1121                    let right_str = self.value_to_string_for_concat(&right)?;
1122                    let cap = left_str.len().saturating_add(right_str.len());
1123                    self.budgets.charge_mem_bytes(cap)?;
1124                    let mut combined = String::with_capacity(cap);
1125                    combined.push_str(left_str.as_ref());
1126                    combined.push_str(right_str.as_ref());
1127                    let result = Value::string(combined);
1128                    self.set_register(dest, result)?;
1129                }
1130
1131                Instruction::GetIndex(dest, array_reg, index_reg) => {
1132                    let collection = self.get_register(array_reg)?.clone();
1133                    let index = self.get_register(index_reg)?.clone();
1134                    let result = if let Some(map_val) = Self::lua_table_map(&collection) {
1135                        if let Value::Map(map) = map_val {
1136                            let raw_key = self.make_hash_key(&Self::lua_table_key_value(&index))?;
1137                            let borrowed = map.borrow();
1138                            borrowed.get(&raw_key).cloned().unwrap_or(Value::Nil)
1139                        } else {
1140                            return Err(LustError::RuntimeError {
1141                                message: format!("Cannot index {:?}", collection.type_of()),
1142                            });
1143                        }
1144                    } else {
1145                        match collection {
1146                            Value::Array(arr) => {
1147                                let idx = index.as_int().ok_or_else(|| LustError::RuntimeError {
1148                                    message: "Array index must be an integer".to_string(),
1149                                })?;
1150                                let borrowed = arr.borrow();
1151                                if idx < 0 || idx as usize >= borrowed.len() {
1152                                    return Err(LustError::RuntimeError {
1153                                        message: format!(
1154                                            "Array index {} out of bounds (length: {})",
1155                                            idx,
1156                                            borrowed.len()
1157                                        ),
1158                                    });
1159                                }
1160
1161                                borrowed[idx as usize].clone()
1162                            }
1163
1164                            Value::Map(map) => {
1165                                let key = self.make_hash_key(&index)?;
1166                                map.borrow().get(&key).cloned().unwrap_or(Value::Nil)
1167                            }
1168
1169                            _ => {
1170                                return Err(LustError::RuntimeError {
1171                                    message: format!("Cannot index {:?}", collection.type_of()),
1172                                })
1173                            }
1174                        }
1175                    };
1176                    self.set_register(dest, result)?;
1177                }
1178
1179                Instruction::ArrayLen(dest, array_reg) => {
1180                    let collection = self.get_register(array_reg)?;
1181                    match collection {
1182                        Value::Array(arr) => {
1183                            let len = int_from_usize(arr.borrow().len());
1184                            self.set_register(dest, Value::Int(len))?;
1185                        }
1186
1187                        _ => {
1188                            return Err(LustError::RuntimeError {
1189                                message: format!(
1190                                    "ArrayLen requires array, got {:?}",
1191                                    collection.type_of()
1192                                ),
1193                            });
1194                        }
1195                    }
1196                }
1197
1198                Instruction::CallMethod(
1199                    obj_reg,
1200                    method_name_idx,
1201                    first_arg,
1202                    arg_count,
1203                    dest_reg,
1204                ) => {
1205                    let object = self.get_register(obj_reg)?.clone();
1206                    let method_name = {
1207                        let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1208                        func.chunk.constants[method_name_idx as usize]
1209                            .as_string()
1210                            .ok_or_else(|| LustError::RuntimeError {
1211                                message: "Method name must be a string".to_string(),
1212                            })?
1213                            .to_string()
1214                    };
1215                    if let Value::Struct {
1216                        name: struct_name, ..
1217                    } = &object
1218                    {
1219                        let mangled_name = format!("{}:{}", struct_name, method_name);
1220                        if let Some(func_idx) =
1221                            self.functions.iter().position(|f| f.name == mangled_name)
1222                        {
1223                            let register_count = self.functions[func_idx].register_count;
1224                            let mut frame = CallFrame::new(func_idx, Some(dest_reg), register_count);
1225                            frame.registers[0] = object.clone();
1226                            for i in 0..arg_count {
1227                                frame.registers[(i + 1) as usize] =
1228                                    self.get_register(first_arg + i)?.clone();
1229                            }
1230
1231                            self.call_stack.push(frame);
1232                            continue;
1233                        }
1234
1235                        let mut candidate_names = vec![mangled_name.clone()];
1236                        if let Some(simple) = struct_name.rsplit(|c| c == '.' || c == ':').next() {
1237                            candidate_names.push(format!("{}:{}", simple, method_name));
1238                        }
1239
1240                        let mut handled = false;
1241                        for candidate in candidate_names {
1242                            let mut resolved = None;
1243                            for variant in [candidate.clone(), candidate.replace('.', "::")] {
1244                                if let Some((_name, value)) =
1245                                    self.globals.iter().find(|(name, _)| *name == &variant)
1246                                {
1247                                    resolved = Some(value.clone());
1248                                    break;
1249                                }
1250                                if let Some((_name, value)) =
1251                                    self.natives.iter().find(|(name, _)| *name == &variant)
1252                                {
1253                                    resolved = Some(value.clone());
1254                                    break;
1255                                }
1256                            }
1257
1258                            if let Some(global_func) = resolved {
1259                                let mut call_args = Vec::with_capacity(1 + arg_count as usize);
1260                                call_args.push(object.clone());
1261                                for i in 0..arg_count {
1262                                    call_args.push(self.get_register(first_arg + i)?.clone());
1263                                }
1264                                let result = self.call_value(&global_func, call_args)?;
1265                                self.set_register(dest_reg, result)?;
1266                                handled = true;
1267                                break;
1268                            }
1269                        }
1270                        if handled {
1271                            continue;
1272                        }
1273                    }
1274
1275                    let mut args = Vec::new();
1276                    for i in 0..arg_count {
1277                        args.push(self.get_register(first_arg + i)?.clone());
1278                    }
1279
1280                    let result = self.call_builtin_method(&object, &method_name, args)?;
1281                    self.set_register(dest_reg, result)?;
1282                }
1283
1284                Instruction::Closure(dest, func_idx, first_upvalue_reg, upvalue_count) => {
1285                    use crate::bytecode::Upvalue;
1286                    self.budgets
1287                        .charge_upvalues_estimate(upvalue_count as usize)?;
1288                    let mut upvalues = Vec::with_capacity(upvalue_count as usize);
1289                    for i in 0..upvalue_count {
1290                        let value = self.get_register(first_upvalue_reg + i)?.clone();
1291                        upvalues.push(Upvalue::new(value));
1292                    }
1293
1294                    let closure = Value::Closure {
1295                        function_idx: func_idx as usize,
1296                        upvalues: Rc::new(upvalues),
1297                    };
1298                    self.set_register(dest, closure)?;
1299                }
1300
1301                Instruction::LoadUpvalue(dest, upvalue_idx) => {
1302                    let frame = self
1303                        .call_stack
1304                        .last()
1305                        .ok_or_else(|| LustError::RuntimeError {
1306                            message: "Empty call stack".to_string(),
1307                        })?;
1308                    if (upvalue_idx as usize) < frame.upvalues.len() {
1309                        let value = frame.upvalues[upvalue_idx as usize].clone();
1310                        self.set_register(dest, value)?;
1311                    } else {
1312                        return Err(LustError::RuntimeError {
1313                            message: format!(
1314                                "Upvalue index {} out of bounds (have {} upvalues)",
1315                                upvalue_idx,
1316                                frame.upvalues.len()
1317                            ),
1318                        });
1319                    }
1320                }
1321
1322                Instruction::StoreUpvalue(upvalue_idx, src) => {
1323                    let value = self.get_register(src)?.clone();
1324                    let frame =
1325                        self.call_stack
1326                            .last_mut()
1327                            .ok_or_else(|| LustError::RuntimeError {
1328                                message: "Empty call stack".to_string(),
1329                            })?;
1330                    if (upvalue_idx as usize) < frame.upvalues.len() {
1331                        frame.upvalues[upvalue_idx as usize] = value;
1332                    } else {
1333                        return Err(LustError::RuntimeError {
1334                            message: format!(
1335                                "Upvalue index {} out of bounds (have {} upvalues)",
1336                                upvalue_idx,
1337                                frame.upvalues.len()
1338                            ),
1339                        });
1340                    }
1341                }
1342
1343                Instruction::SetIndex(collection_reg, index_reg, value_reg) => {
1344                    let collection = self.get_register(collection_reg)?.clone();
1345                    let index = self.get_register(index_reg)?.clone();
1346                    let value = self.get_register(value_reg)?.clone();
1347                    if let Some(map_val) = Self::lua_table_map(&collection) {
1348                        if let Value::Map(map) = map_val {
1349                            let key = self.make_hash_key(&Self::lua_table_key_value(&index))?;
1350                            if self.budgets.mem_budget_enabled() && !map.borrow().contains_key(&key)
1351                            {
1352                                self.budgets.charge_map_entry_estimate()?;
1353                            }
1354                            map.borrow_mut().insert(key, value);
1355                        } else {
1356                            return Err(LustError::RuntimeError {
1357                                message: format!("Cannot index {:?}", collection.type_of()),
1358                            });
1359                        }
1360                    } else {
1361                        match collection {
1362                            Value::Array(arr) => {
1363                                let idx = index.as_int().ok_or_else(|| LustError::RuntimeError {
1364                                    message: "Array index must be an integer".to_string(),
1365                                })?;
1366                                let mut borrowed = arr.borrow_mut();
1367                                if idx < 0 || idx as usize >= borrowed.len() {
1368                                    return Err(LustError::RuntimeError {
1369                                        message: format!(
1370                                            "Array index {} out of bounds (length: {})",
1371                                            idx,
1372                                            borrowed.len()
1373                                        ),
1374                                    });
1375                                }
1376
1377                                borrowed[idx as usize] = value;
1378                            }
1379
1380                            Value::Map(map) => {
1381                                let key = self.make_hash_key(&index)?;
1382                                if self.budgets.mem_budget_enabled()
1383                                    && !map.borrow().contains_key(&key)
1384                                {
1385                                    self.budgets.charge_map_entry_estimate()?;
1386                                }
1387                                map.borrow_mut().insert(key, value);
1388                            }
1389
1390                            _ => {
1391                                return Err(LustError::RuntimeError {
1392                                    message: format!("Cannot index {:?}", collection.type_of()),
1393                                })
1394                            }
1395                        }
1396                    }
1397                }
1398
1399                Instruction::TypeIs(dest, value_reg, type_name_idx) => {
1400                    let value = self.get_register(value_reg)?.clone();
1401                    let func = &self.functions[self.call_stack.last().unwrap().function_idx];
1402                    let type_name = func.chunk.constants[type_name_idx as usize]
1403                        .as_string()
1404                        .ok_or_else(|| LustError::RuntimeError {
1405                            message: "Type name must be a string".to_string(),
1406                        })?
1407                        .to_string();
1408                    let matches = self.value_is_type(&value, &type_name);
1409                    self.set_register(dest, Value::Bool(matches))?;
1410                }
1411            }
1412
1413            if self.jit.enabled {
1414                if let Some(recorder) = &mut self.trace_recorder {
1415                    if recorder.is_recording() {
1416                        if self.skip_next_trace_record {
1417                            self.skip_next_trace_record = false;
1418                        } else {
1419                            let function = &self.functions[func_idx];
1420                            let registers_opt =
1421                                if let Some(frame) = self.call_stack.get(executing_frame_index) {
1422                                    Some(&frame.registers)
1423                                } else if executing_frame_index > 0 {
1424                                    self.call_stack
1425                                        .get(executing_frame_index - 1)
1426                                        .map(|frame| &frame.registers)
1427                                } else {
1428                                    None
1429                                };
1430                            if let Some(registers) = registers_opt {
1431                                if let Err(e) = recorder.record_instruction(
1432                                    instruction,
1433                                    ip_before_execution,
1434                                    registers,
1435                                    function,
1436                                    func_idx,
1437                                    &self.functions,
1438                                ) {
1439                                    crate::jit::log(|| format!("⚠️  JIT: {}", e));
1440                                    self.trace_recorder = None;
1441                                }
1442                            }
1443                        }
1444                    }
1445                }
1446            }
1447        }
1448    }
1449
1450    pub(super) fn binary_op<F>(
1451        &mut self,
1452        dest: Register,
1453        lhs: Register,
1454        rhs: Register,
1455        op: F,
1456    ) -> Result<()>
1457    where
1458        F: FnOnce(&Value, &Value) -> Result<Value>,
1459    {
1460        let left = self.get_register(lhs)?;
1461        let right = self.get_register(rhs)?;
1462        let result = op(left, right)?;
1463        self.set_register(dest, result)
1464    }
1465
1466    pub(super) fn comparison_op<F>(
1467        &mut self,
1468        dest: Register,
1469        lhs: Register,
1470        rhs: Register,
1471        op: F,
1472    ) -> Result<()>
1473    where
1474        F: FnOnce(LustFloat, LustFloat) -> bool,
1475    {
1476        let left = self.get_register(lhs)?;
1477        let right = self.get_register(rhs)?;
1478        let result = match (left, right) {
1479            (Value::Int(a), Value::Int(b)) => op(float_from_int(*a), float_from_int(*b)),
1480            (Value::Float(a), Value::Float(b)) => op(*a, *b),
1481            (Value::Int(a), Value::Float(b)) => op(float_from_int(*a), *b),
1482            (Value::Float(a), Value::Int(b)) => op(*a, float_from_int(*b)),
1483            _ => {
1484                return Err(LustError::RuntimeError {
1485                    message: format!("Cannot compare {:?} and {:?}", left, right),
1486                })
1487            }
1488        };
1489        self.set_register(dest, Value::Bool(result))
1490    }
1491
1492    pub(super) fn value_is_type(&self, value: &Value, type_name: &str) -> bool {
1493        if let Some(matches) = self.match_function_type(value, type_name) {
1494            return matches;
1495        }
1496
1497        let value_type_name = match value {
1498            Value::Int(_) => "int",
1499            Value::Float(_) => "float",
1500            Value::String(_) => "string",
1501            Value::Bool(_) => "bool",
1502            Value::Nil => "nil",
1503            Value::Array(_) => "Array",
1504            Value::Tuple(_) => "Tuple",
1505            Value::Map(_) => "Map",
1506            Value::Struct { name, .. } => name.as_str(),
1507            Value::WeakStruct(weak) => weak.struct_name(),
1508            Value::Enum { enum_name, .. } => enum_name.as_str(),
1509            Value::Function(_) | Value::NativeFunction(_) | Value::Closure { .. } => "function",
1510            Value::Iterator(_) => "Iterator",
1511            Value::Task(_) => "task",
1512        };
1513        if value_type_name == type_name {
1514            return true;
1515        }
1516
1517        if type_name.starts_with("Array") && matches!(value, Value::Array(_)) {
1518            return true;
1519        }
1520
1521        if type_name.starts_with("Map") && matches!(value, Value::Map(_)) {
1522            return true;
1523        }
1524
1525        if type_name.starts_with("Tuple") && matches!(value, Value::Tuple(_)) {
1526            return true;
1527        }
1528
1529        if type_name == "Option"
1530            && matches!(value, Value::Enum { enum_name, .. } if enum_name == "Option")
1531        {
1532            return true;
1533        }
1534
1535        if type_name == "Result"
1536            && matches!(value, Value::Enum { enum_name, .. } if enum_name == "Result")
1537        {
1538            return true;
1539        }
1540
1541        if type_name == "unknown" {
1542            return true;
1543        }
1544
1545        if let Some(_) = self
1546            .trait_impls
1547            .get(&(value_type_name.to_string(), type_name.to_string()))
1548        {
1549            return true;
1550        }
1551
1552        false
1553    }
1554
1555    fn value_trait_name(&self, value: &Value) -> String {
1556        match value {
1557            Value::Int(_) => "int".to_string(),
1558            Value::Float(_) => "float".to_string(),
1559            Value::String(_) => "string".to_string(),
1560            Value::Bool(_) => "bool".to_string(),
1561            Value::Nil => "nil".to_string(),
1562            Value::Array(_) => "Array".to_string(),
1563            Value::Tuple(_) => "Tuple".to_string(),
1564            Value::Map(_) => "Map".to_string(),
1565            Value::Struct { name, .. } => name.clone(),
1566            Value::WeakStruct(weak) => weak.struct_name().to_string(),
1567            Value::Enum { enum_name, .. } => enum_name.clone(),
1568            Value::Function(_) | Value::NativeFunction(_) | Value::Closure { .. } => {
1569                "function".to_string()
1570            }
1571            Value::Iterator(_) => "Iterator".to_string(),
1572            Value::Task(_) => "task".to_string(),
1573        }
1574    }
1575
1576    fn invoke_hashkey(&mut self, value: &Value, type_name: &str) -> Result<Value> {
1577        let mut candidates = vec![format!("{}:{}", type_name, HASH_KEY_METHOD)];
1578        if let Some(last) = type_name.rsplit('.').next() {
1579            if last != type_name {
1580                candidates.push(format!("{}:{}", last, HASH_KEY_METHOD));
1581            }
1582        }
1583
1584        for candidate in candidates {
1585            if let Some(idx) = self.functions.iter().position(|f| f.name == candidate) {
1586                return self.call_value(&Value::Function(idx), vec![value.clone()]);
1587            }
1588        }
1589
1590        Err(LustError::RuntimeError {
1591            message: format!(
1592                "HashKey trait declared but method '{}' not found for type '{}'",
1593                HASH_KEY_METHOD, type_name
1594            ),
1595        })
1596    }
1597
1598    pub(super) fn make_hash_key(&mut self, value: &Value) -> Result<ValueKey> {
1599        let type_name = self.value_trait_name(value);
1600        if self.type_has_hashkey(&type_name) {
1601            let hashed = self.invoke_hashkey(value, &type_name)?;
1602            Ok(ValueKey::with_hashed(value.clone(), hashed))
1603        } else {
1604            Ok(ValueKey::from_value(value))
1605        }
1606    }
1607
1608    fn match_function_type(&self, value: &Value, type_name: &str) -> Option<bool> {
1609        let wants_signature = type_name.starts_with("function(");
1610        let wants_generic = type_name == "function";
1611        if !wants_signature && !wants_generic {
1612            return None;
1613        }
1614
1615        let matches = match value {
1616            Value::Function(idx) => self.function_signature_matches(*idx, type_name),
1617            Value::Closure { function_idx, .. } => {
1618                self.function_signature_matches(*function_idx, type_name)
1619            }
1620            Value::NativeFunction(_) => wants_generic,
1621            _ => false,
1622        };
1623        Some(matches)
1624    }
1625
1626    fn function_signature_matches(&self, func_idx: usize, type_name: &str) -> bool {
1627        if type_name == "function" {
1628            return true;
1629        }
1630
1631        self.functions
1632            .get(func_idx)
1633            .and_then(|func| func.signature.as_ref())
1634            .map(|signature| signature.to_string() == type_name)
1635            .unwrap_or(false)
1636    }
1637
1638    pub(super) fn get_register(&self, reg: Register) -> Result<&Value> {
1639        let frame = self
1640            .call_stack
1641            .last()
1642            .ok_or_else(|| LustError::RuntimeError {
1643                message: "Empty call stack".to_string(),
1644            })?;
1645        Ok(&frame.registers[reg as usize])
1646    }
1647
1648    pub(super) fn set_register(&mut self, reg: Register, value: Value) -> Result<()> {
1649        self.observe_value(&value);
1650        let frame = self
1651            .call_stack
1652            .last_mut()
1653            .ok_or_else(|| LustError::RuntimeError {
1654                message: "Empty call stack".to_string(),
1655            })?;
1656        frame.registers[reg as usize] = value;
1657        self.maybe_collect_cycles();
1658        Ok(())
1659    }
1660
1661    pub(super) fn handle_native_call_outcome(
1662        &mut self,
1663        dest: Register,
1664        outcome: NativeCallResult,
1665    ) -> Result<()> {
1666        #[cfg(feature = "std")]
1667        if std::env::var_os("LUST_LUA_SOCKET_TRACE").is_some() {
1668            if let NativeCallResult::Return(value) = &outcome {
1669                if let Value::Array(arr) = value {
1670                    let borrowed = arr.borrow();
1671                    let interesting = borrowed.len() > 1
1672                        && matches!(
1673                            borrowed.get(0),
1674                            Some(Value::Enum { enum_name, variant, .. })
1675                                if enum_name == "LuaValue" && variant == "Nil"
1676                        );
1677                    if interesting {
1678                        let func_name = self
1679                            .call_stack
1680                            .last()
1681                            .and_then(|frame| self.functions.get(frame.function_idx))
1682                            .map(|f| f.name.as_str())
1683                            .unwrap_or("<unknown>");
1684                        eprintln!(
1685                            "[lua-socket] native return in {} dest=R{} len={} value={}",
1686                            func_name,
1687                            dest,
1688                            borrowed.len(),
1689                            value
1690                        );
1691                    }
1692                }
1693            }
1694        }
1695        match outcome {
1696            NativeCallResult::Return(value) => self.set_register(dest, value),
1697            NativeCallResult::Yield(value) => {
1698                if self.current_task.is_some() {
1699                    self.set_register(dest, Value::Nil)?;
1700                    self.pending_task_signal = Some(TaskSignal::Yield { dest, value });
1701                    Ok(())
1702                } else {
1703                    Err(LustError::RuntimeError {
1704                        message: "task.yield() can only be used inside a task".to_string(),
1705                    })
1706                }
1707            }
1708
1709            NativeCallResult::Stop(value) => {
1710                if self.current_task.is_some() {
1711                    self.set_register(dest, Value::Nil)?;
1712                    self.pending_task_signal = Some(TaskSignal::Stop { value });
1713                    Ok(())
1714                } else {
1715                    Err(LustError::RuntimeError {
1716                        message: "task.stop() can only be used inside a task".to_string(),
1717                    })
1718                }
1719            }
1720        }
1721    }
1722
1723    pub fn value_to_string_for_concat(&mut self, value: &Value) -> Result<Rc<String>> {
1724        match value {
1725            Value::String(s) => Ok(s.clone()),
1726            Value::Struct { name, .. } => self.invoke_tostring(value, name),
1727            Value::Enum { enum_name, .. } => self.invoke_tostring(value, enum_name),
1728            _ => Ok(Rc::new(value.to_string())),
1729        }
1730    }
1731
1732    #[inline(never)]
1733    pub fn call_value(&mut self, func: &Value, args: Vec<Value>) -> Result<Value> {
1734        // Lua compatibility: honor __call metamethod on Lua tables/userdata.
1735        // Lua semantics: if value has metatable.__call, calling it invokes that function with the
1736        // receiver as the first argument.
1737        let mut args = args;
1738        let maybe_lua_call = {
1739            let mut current = func;
1740            let mut receiver_wrapped = func.clone();
1741
1742            if let Value::Struct { name, .. } = func {
1743                if name == "LuaTable" {
1744                    receiver_wrapped = Value::enum_variant("LuaValue", "Table", vec![func.clone()]);
1745                } else if name == "LuaUserdata" {
1746                    receiver_wrapped =
1747                        Value::enum_variant("LuaValue", "Userdata", vec![func.clone()]);
1748                }
1749            }
1750
1751            if let Value::Enum {
1752                enum_name,
1753                variant,
1754                values,
1755            } = func
1756            {
1757                if enum_name == "LuaValue" && (variant == "Table" || variant == "Userdata") {
1758                    if let Some(inner) = values.as_ref().and_then(|vals| vals.get(0)) {
1759                        current = inner;
1760                    }
1761                }
1762            }
1763
1764            if let Value::Struct { name, .. } = current {
1765                if name == "LuaTable" || name == "LuaUserdata" {
1766                    if let Some(Value::Map(meta_rc)) = current.struct_get_field("metamethods") {
1767                        meta_rc
1768                            .borrow()
1769                            .get(&ValueKey::string("__call".to_string()))
1770                            .cloned()
1771                            .map(|callable| (callable, receiver_wrapped))
1772                    } else {
1773                        None
1774                    }
1775                } else {
1776                    None
1777                }
1778            } else {
1779                None
1780            }
1781        };
1782
1783        if let Some((callable, receiver)) = maybe_lua_call {
1784            // eprintln!("DEBUG: __call metamethod found, invoking with receiver");
1785            let mut call_args = Vec::with_capacity(args.len() + 1);
1786            call_args.push(receiver);
1787            call_args.append(&mut args);
1788            return self.call_value(&callable, call_args);
1789        } else {
1790            // if let Value::Struct { name, .. } = func {
1791            //     if name == "LuaTable" || name == "LuaUserdata" {
1792            //         eprintln!("DEBUG: Calling LuaTable/Userdata but no __call found in metamethods");
1793            //     }
1794            // }
1795        }
1796
1797        match func {
1798            #[cfg(all(feature = "std", not(target_arch = "wasm32")))]
1799            Value::Enum {
1800                enum_name,
1801                variant,
1802                values,
1803            } if enum_name == "LuaValue" && variant == "Function" => {
1804                let handle = values
1805                    .as_ref()
1806                    .and_then(|vals| vals.get(0))
1807                    .and_then(|v| v.struct_get_field("handle"))
1808                    .and_then(|v| v.as_int())
1809                    .map(|i| i as usize)
1810                    .ok_or_else(|| LustError::RuntimeError {
1811                        message: "LuaValue function missing handle".to_string(),
1812                    })?;
1813                let inner = crate::lua_compat::lookup_lust_function(handle).ok_or_else(|| {
1814                    LustError::RuntimeError {
1815                        message: format!(
1816                            "LuaValue function handle {} was not registered with VM",
1817                            handle
1818                        ),
1819                    }
1820                })?;
1821                return self.call_value(&inner, args);
1822            }
1823            Value::Function(func_idx) => {
1824                let saved_pending_return_value = self.pending_return_value.clone();
1825                let saved_pending_return_dest = self.pending_return_dest;
1826                let saved_pending_task_signal = self.pending_task_signal.clone();
1827                let saved_last_task_signal = self.last_task_signal.clone();
1828
1829                let register_count = self.functions[*func_idx].register_count;
1830                let mut frame = CallFrame::new(*func_idx, None, register_count);
1831                for (i, arg) in args.into_iter().enumerate() {
1832                    frame.registers[i] = arg;
1833                }
1834
1835                let stack_depth_before = self.call_stack.len();
1836                self.call_stack.push(frame);
1837                let previous_target = self.call_until_depth;
1838                self.call_until_depth = Some(stack_depth_before);
1839                let run_result = self.run();
1840                self.call_until_depth = previous_target;
1841                match run_result {
1842                    Ok(value) => Ok(value),
1843                    Err(err) => {
1844                        let annotated = self.annotate_runtime_error(err);
1845                        while self.call_stack.len() > stack_depth_before {
1846                            self.call_stack.pop();
1847                        }
1848                        self.pending_return_value = saved_pending_return_value;
1849                        self.pending_return_dest = saved_pending_return_dest;
1850                        self.pending_task_signal = saved_pending_task_signal;
1851                        self.last_task_signal = saved_last_task_signal;
1852                        Err(annotated)
1853                    }
1854                }
1855            }
1856
1857            Value::Closure {
1858                function_idx: func_idx,
1859                upvalues,
1860            } => {
1861                let saved_pending_return_value = self.pending_return_value.clone();
1862                let saved_pending_return_dest = self.pending_return_dest;
1863                let saved_pending_task_signal = self.pending_task_signal.clone();
1864                let saved_last_task_signal = self.last_task_signal.clone();
1865
1866                let upvalue_values: Vec<Value> = upvalues.iter().map(|uv| uv.get()).collect();
1867                let register_count = self.functions[*func_idx].register_count;
1868                let mut frame = CallFrame::new(*func_idx, None, register_count);
1869                frame.upvalues = upvalue_values;
1870                for (i, arg) in args.into_iter().enumerate() {
1871                    frame.registers[i] = arg;
1872                }
1873
1874                let stack_depth_before = self.call_stack.len();
1875                self.call_stack.push(frame);
1876                let previous_target = self.call_until_depth;
1877                self.call_until_depth = Some(stack_depth_before);
1878                let run_result = self.run();
1879                self.call_until_depth = previous_target;
1880                match run_result {
1881                    Ok(value) => Ok(value),
1882                    Err(err) => {
1883                        let annotated = self.annotate_runtime_error(err);
1884                        while self.call_stack.len() > stack_depth_before {
1885                            self.call_stack.pop();
1886                        }
1887                        self.pending_return_value = saved_pending_return_value;
1888                        self.pending_return_dest = saved_pending_return_dest;
1889                        self.pending_task_signal = saved_pending_task_signal;
1890                        self.last_task_signal = saved_last_task_signal;
1891                        Err(annotated)
1892                    }
1893                }
1894            }
1895
1896            Value::NativeFunction(native_fn) => {
1897                self.push_current_vm();
1898                let outcome = native_fn(&args);
1899                self.pop_current_vm();
1900                let outcome = outcome.map_err(|e| LustError::RuntimeError { message: e })?;
1901                match outcome {
1902                    NativeCallResult::Return(value) => Ok(value),
1903                    NativeCallResult::Yield(_) | NativeCallResult::Stop(_) => {
1904                        Err(LustError::RuntimeError {
1905                            message: "Yielding or stopping is not allowed from this context"
1906                                .to_string(),
1907                        })
1908                    }
1909                }
1910            }
1911
1912            _ => Err(LustError::RuntimeError {
1913                message: format!("Cannot call non-function value: {:?}", func),
1914            }),
1915        }
1916    }
1917}