Skip to main content

luau_vm/vm/
execute.rs

1use crate::ObjectMemberLookup;
2use crate::call::{CallRuntime, ThreadStack};
3use crate::class::ClassRuntime;
4use crate::debug::DebugRuntime;
5use crate::function::FunctionRuntime;
6use crate::function::{Closure, Proto};
7use crate::gc::GcObject;
8use crate::gc::{GcBarrier, GcRuntime};
9use crate::handle::RawHandle;
10use crate::handle::sealed::Sealed;
11use crate::metamethod::{MetamethodRuntime, TmEvent};
12use crate::native::NativeCallContext;
13use crate::state::ThreadState;
14use crate::state::{LUA_CALLINFO_NATIVE, LUA_CALLINFO_OP_YIELD};
15use crate::table::TableRuntime;
16use crate::thread::{LUA_MULTRET, Thread};
17use crate::types::{
18    LUA_TBOOLEAN, LUA_TBUFFER, LUA_TCLASS, LUA_TFUNCTION, LUA_TINTEGER, LUA_TLIGHTUSERDATA,
19    LUA_TNIL, LUA_TNUMBER, LUA_TOBJECT, LUA_TSTRING, LUA_TTABLE, LUA_TTHREAD, LUA_TUSERDATA,
20    LUA_TVECTOR, LUA_VECTOR_SIZE,
21};
22use crate::userdata::{LuaUserdataDirectFieldGet, USERDATA_TAG_LIMIT, UserdataDirectFieldResult};
23use crate::value::{RAW_TVALUE_NIL, RawTValue, TValue, TValueCursor, nil_object};
24use crate::vm::{VmCallFrame, VmOperations, string_compare};
25use crate::{VmExit, VmResult};
26use luau_bytecode::model::{Instruction, InstructionAux};
27use luau_bytecode::opcodes::Opcode;
28use luau_common::flags;
29use std::mem;
30use std::ptr;
31
32const LCT_VAL: u8 = 0;
33const LCT_REF: u8 = 1;
34const LCT_UPVAL: u8 = 2;
35
36/// Unstable bytecode execution capability.
37///
38/// # Safety
39///
40/// The thread's current call frame, stack, saved program counter, closure, and
41/// bytecode graph must form a valid VM execution state. Execution may mutate
42/// or relocate all VM state and invalidate unrooted handles and cursors.
43#[allow(
44    clippy::missing_safety_doc,
45    reason = "all methods share the capability-level safety contract"
46)]
47pub trait VmExecution: Sealed {
48    /// `luau_execute`
49    unsafe fn execute(&self) -> VmResult;
50
51    /// `luau_finishop`
52    unsafe fn finish_op(&self) -> VmResult;
53}
54
55trait InstructionWordExt {
56    fn word(self) -> u32;
57    fn opcode(self) -> Opcode;
58    fn a(self) -> u8;
59    fn b(self) -> u8;
60    fn c(self) -> u8;
61    fn d(self) -> i16;
62    fn e(self) -> i32;
63}
64
65impl InstructionWordExt for u32 {
66    fn word(self) -> u32 {
67        self
68    }
69
70    fn opcode(self) -> Opcode {
71        decode_instruction_opcode(Instruction::new(self))
72    }
73
74    fn a(self) -> u8 {
75        Instruction::new(self).a()
76    }
77
78    fn b(self) -> u8 {
79        Instruction::new(self).b()
80    }
81
82    fn c(self) -> u8 {
83        Instruction::new(self).c()
84    }
85
86    fn d(self) -> i16 {
87        Instruction::new(self).d()
88    }
89
90    fn e(self) -> i32 {
91        Instruction::new(self).e()
92    }
93}
94
95trait InstructionBits {
96    fn bits(self) -> u32;
97}
98
99impl InstructionBits for u32 {
100    fn bits(self) -> u32 {
101        self
102    }
103}
104
105impl InstructionBits for Instruction {
106    fn bits(self) -> u32 {
107        self.word()
108    }
109}
110
111#[inline(always)]
112fn v_skip_step(op: Opcode) -> bool {
113    matches!(op, Opcode::PrepVarargs | Opcode::Break)
114}
115
116impl Proto {
117    /// `VM_KV`
118    #[inline(always)]
119    fn vm_const(&self, constants: TValueCursor, index: usize) -> TValue {
120        debug_assert!(index < unsafe { self.as_ptr().as_ref().unwrap_unchecked().size_k as usize });
121        unsafe { constants.add(index).value_unchecked() }
122    }
123
124    /// `VM_ASSERT_PC`
125    fn assert_vm_pc(&self, pc: *const u32) {
126        let code = unsafe { self.as_ptr().as_ref().unwrap_unchecked().code }.cast_const();
127        let size = unsafe { self.as_ptr().as_ref().unwrap_unchecked().size_code as usize };
128        debug_assert!(pc >= code);
129        debug_assert!(unsafe { pc.offset_from(code) as usize } < size);
130    }
131}
132
133impl TValueCursor {
134    fn vm_reg_cursor(self, top: TValueCursor, index: usize) -> TValueCursor {
135        debug_assert!(index < unsafe { top.offset_from(self) as usize });
136        unsafe { self.add(index) }
137    }
138}
139
140impl TValue {
141    // lobject.h: vvalue(o) returns a contiguous float view over value.v + TValue::extra.
142    #[inline(always)]
143    unsafe fn vector_ptr(&self) -> *const f32 {
144        debug_assert_eq!(self.tt(), LUA_TVECTOR);
145        unsafe { (&raw const self.as_ptr().as_ref().unwrap_unchecked().value.vector).cast::<f32>() }
146    }
147
148    #[inline(always)]
149    unsafe fn vector_eq(&self, rhs: TValue) -> bool {
150        unsafe {
151            let lhs = self.vector_ptr();
152            let rhs = rhs.vector_ptr();
153
154            #[cfg(feature = "vector4")]
155            {
156                *lhs == *rhs
157                    && *lhs.add(1) == *rhs.add(1)
158                    && *lhs.add(2) == *rhs.add(2)
159                    && vector_w_ptr(lhs) == vector_w_ptr(rhs)
160            }
161
162            #[cfg(not(feature = "vector4"))]
163            {
164                *lhs == *rhs && *lhs.add(1) == *rhs.add(1) && *lhs.add(2) == *rhs.add(2)
165            }
166        }
167    }
168
169    /// `setvvalue`
170    #[inline(always)]
171    fn set_vector4(&self, x: f32, y: f32, z: f32, w: f32) {
172        #[cfg(not(feature = "vector4"))]
173        {
174            let _ = w;
175            self.set_vector([x, y, z]);
176        }
177
178        #[cfg(feature = "vector4")]
179        self.set_vector([x, y, z, w]);
180    }
181}
182
183#[cfg(feature = "vector4")]
184#[inline(always)]
185unsafe fn vector_w_ptr(value: *const f32) -> f32 {
186    unsafe { *value.add(3) }
187}
188
189#[cfg(not(feature = "vector4"))]
190#[inline(always)]
191unsafe fn vector_w_ptr(_value: *const f32) -> f32 {
192    0.0
193}
194
195impl Thread {
196    /// `VM_PROTECT_PC`
197    #[inline(always)]
198    fn set_vm_saved_pc<T>(&self, pc: *const T) {
199        unsafe {
200            self.current_call_info().set_saved_pc(pc.cast());
201        }
202    }
203
204    /// `VM_INTERRUPT`
205    #[inline(always)]
206    fn interrupt_vm(&self, pc: *const u32) -> VmResult {
207        let global = unsafe { self.global() };
208        let Some(interrupt) = global.take_execution_interrupt_callback() else {
209            return Ok(());
210        };
211
212        unsafe { self.interrupt_vm_slow(pc, interrupt) }
213    }
214
215    #[cold]
216    #[inline(never)]
217    unsafe fn interrupt_vm_slow(
218        &self,
219        pc: *const u32,
220        interrupt: fn(&Thread) -> VmResult,
221    ) -> VmResult {
222        unsafe {
223            self.current_call_info().set_saved_pc(pc.add(1));
224            let result = interrupt(self);
225            if let Err(exit @ VmExit::Control(_)) = result {
226                let current_call_info = self.current_call_info();
227                current_call_info.set_saved_pc(current_call_info.saved_pc().sub(1));
228                return Err(exit);
229            }
230
231            result
232        }
233    }
234
235    unsafe fn tm_by_obj_or_nil(&self, object: TValue, event: TmEvent) -> TValue {
236        unsafe { self.get_tm_by_obj(object, event).unwrap_or_else(nil_object) }
237    }
238
239    #[cold]
240    #[inline(never)]
241    unsafe fn finish_native_call(&self, called_closure: Closure, nresults: i32) -> VmResult {
242        unsafe {
243            let native_function = called_closure.native_data().function.unwrap_unchecked();
244            let produced = native_function(NativeCallContext::new(self))?;
245
246            let call_info = self.current_call_info();
247            let parent_cursor = self.current_call_info_cursor().sub(1);
248            let parent = parent_cursor.call_info_unchecked();
249
250            let mut result = call_info.function();
251            let mut value = self.stack_top().sub(produced);
252            let value_end = self.stack_top();
253            let mut remaining = nresults;
254
255            while remaining != 0 && value < value_end {
256                result.value_unchecked().set_obj(value.value_unchecked());
257                result = result.add(1);
258                value = value.add(1);
259                remaining -= 1;
260            }
261
262            while remaining > 0 {
263                result.value_unchecked().set_nil();
264                result = result.add(1);
265                remaining -= 1;
266            }
267
268            self.set_current_call_info(parent_cursor);
269            self.set_stack_base(parent.base());
270            self.set_stack_top(if nresults == LUA_MULTRET {
271                result
272            } else {
273                parent.top()
274            });
275            Ok(())
276        }
277    }
278
279    pub(crate) unsafe fn execute_thread(&self) -> VmResult {
280        if unsafe { self.as_ptr().as_ref().unwrap_unchecked().single_step } {
281            v_execute_impl::<true>(self)
282        } else {
283            v_execute_impl::<false>(self)
284        }
285    }
286
287    pub(crate) unsafe fn finish_op_thread(&self) -> VmResult {
288        unsafe {
289            let call_info = self.current_call_info();
290            call_info.as_ptr().as_mut().unwrap_unchecked().flags &= !LUA_CALLINFO_OP_YIELD;
291
292            let closure = call_info.function_closure();
293            let base = self.stack_base();
294            let mut pc = call_info.saved_pc();
295            let instruction = *pc.sub(1);
296
297            match decode_instruction_opcode(instruction) {
298                Opcode::ForGLoop => {
299                    let ra = base.vm_reg_cursor(self.stack_top(), instruction.a() as usize);
300
301                    ra.add(2)
302                        .value_unchecked()
303                        .set_obj(ra.add(3).value_unchecked());
304
305                    pc = if ra.add(3).value_unchecked().is_nil() {
306                        pc.add(1)
307                    } else {
308                        pc.offset(instruction.d() as isize)
309                    };
310
311                    closure.proto().unwrap_unchecked().assert_vm_pc(pc);
312                }
313                _ => unreachable!("unknown yielded opcode"),
314            }
315
316            call_info.set_saved_pc(pc);
317        }
318        Ok(())
319    }
320
321    unsafe fn setup_cci(&self, n_results: i32, function: TValueCursor) -> VmResult {
322        unsafe {
323            let call_info = self.incr_ci()?.call_info_unchecked();
324            let closure = function.value_unchecked().closure_value();
325
326            call_info.init_call(
327                function,
328                function.add(1).add(crate::thread::LUA_MIN_STACK),
329                n_results,
330                closure.proto(),
331            );
332
333            self.set_stack_base(function.add(1));
334            self.check_stack_for_new_ci(crate::thread::LUA_MIN_STACK as i32)?;
335
336            debug_assert!(call_info.top() <= self.stack_last());
337            debug_assert!(call_info.function().value_unchecked().is_function());
338        }
339        Ok(())
340    }
341}
342
343impl VmExecution for Thread {
344    /// `luau_execute`
345    unsafe fn execute(&self) -> VmResult {
346        unsafe { self.execute_thread() }
347    }
348
349    /// `luau_finishop`
350    unsafe fn finish_op(&self) -> VmResult {
351        unsafe { self.finish_op_thread() }
352    }
353}
354
355fn patch_instruction_c<T>(instruction: *mut T, c: u8) {
356    unsafe {
357        let instruction = instruction.cast::<Instruction>();
358        *instruction = Instruction::new((*instruction).word()).with_c(c);
359    }
360}
361
362fn patch_instruction_opcode<T>(instruction: *mut T, opcode: Opcode) {
363    unsafe {
364        let instruction = instruction.cast::<Instruction>();
365        *instruction = Instruction::new(((*instruction).word() & !0xff) | opcode as u32);
366    }
367}
368
369fn patch_aux_slot<T>(aux: *mut T, kv: u16, slot: u16) {
370    unsafe {
371        let aux = aux.cast::<Instruction>();
372        *aux = Instruction::new(kv as u32 | ((slot as u32) << 16));
373    }
374}
375
376#[inline(always)]
377fn decode_opcode_byte(opcode: u8) -> Opcode {
378    debug_assert!(usize::from(opcode) < Opcode::COUNT);
379    unsafe { mem::transmute(opcode) }
380}
381
382#[inline(always)]
383fn decode_instruction_opcode<T: InstructionBits>(instruction: T) -> Opcode {
384    decode_opcode_byte((instruction.bits() & 0xff) as u8)
385}
386
387fn v_execute_impl<const SINGLE_STEP: bool>(thread: &Thread) -> VmResult {
388    unsafe {
389        let global = thread.global();
390        let current_call_info = thread.current_call_info();
391
392        debug_assert!(current_call_info.is_lua());
393        debug_assert!(thread.as_ptr().as_ref().unwrap_unchecked().is_active);
394        debug_assert!(!GcObject::from(thread).is_black());
395
396        let mut pc = current_call_info.saved_pc();
397        let mut closure = current_call_info.function_closure();
398        let mut base = thread.stack_base();
399        let mut proto = closure.proto().unwrap_unchecked();
400        let mut constants = proto.constants();
401
402        if current_call_info.as_ptr().as_ref().unwrap_unchecked().flags & LUA_CALLINFO_NATIVE != 0
403            && !SINGLE_STEP
404        {
405            debug_assert!(
406                !proto
407                    .as_ptr()
408                    .as_ref()
409                    .unwrap_unchecked()
410                    .exec_data
411                    .is_null()
412            );
413
414            let Some(enter) = global.execution_enter() else {
415                unreachable!("native lvmexecute requires an execution enter callback");
416            };
417
418            if enter(thread, proto) == 0 {
419                return Ok(());
420            }
421
422            let resumed_call_info = thread.current_call_info();
423            closure = resumed_call_info.function_closure();
424            proto = closure.proto().unwrap_unchecked();
425            pc = resumed_call_info.saved_pc();
426            base = thread.stack_base();
427            constants = proto.constants();
428            proto.assert_vm_pc(pc);
429        }
430
431        'vm: loop {
432            debug_assert!(base == thread.stack_base());
433            debug_assert!(base <= thread.stack_top());
434            debug_assert!(thread.stack_top() <= thread.stack_last());
435
436            let insn_pc = pc;
437            let instruction = { *insn_pc };
438            let opcode = decode_instruction_opcode(instruction);
439            if SINGLE_STEP
440                && let Some(hook) = global.debug_step_callback()
441                && !v_skip_step(opcode)
442            {
443                thread.set_vm_saved_pc(insn_pc);
444                thread.call_hook(hook, ptr::null_mut())?;
445
446                base = thread.stack_base();
447            }
448
449            pc = insn_pc.add(1);
450
451            let mut dispatch_opcode = opcode;
452
453            'dispatch: loop {
454                match dispatch_opcode {
455                    Opcode::Nop => {
456                        debug_assert_eq!(instruction.word(), 0);
457                    }
458                    Opcode::Break => {
459                        let debug_insn = { proto.as_ptr().as_ref().unwrap_unchecked().debug_insn };
460                        debug_assert!(!debug_insn.is_null());
461
462                        let debug_pc = {
463                            insn_pc.offset_from(proto.as_ptr().as_ref().unwrap_unchecked().code)
464                                as usize
465                        };
466                        let original_opcode = { *debug_insn.add(debug_pc) };
467                        debug_assert_ne!(original_opcode, Opcode::Break as u8);
468
469                        if let Some(hook) = global.debug_break_callback() {
470                            thread.set_vm_saved_pc(insn_pc);
471                            thread.call_hook(hook, ptr::null_mut())?;
472
473                            base = thread.stack_base();
474                        }
475
476                        dispatch_opcode = decode_opcode_byte(original_opcode);
477                        continue 'dispatch;
478                    }
479                    Opcode::LoadNil => {
480                        let ra = base
481                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
482                            .value_unchecked();
483                        ra.set_nil();
484                    }
485                    Opcode::LoadB => {
486                        let ra = base
487                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
488                            .value_unchecked();
489                        ra.set_boolean(i32::from(instruction.b()));
490
491                        pc = pc.add(instruction.c() as usize);
492                        proto.assert_vm_pc(pc);
493                    }
494                    Opcode::LoadN => {
495                        let ra = base
496                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
497                            .value_unchecked();
498                        ra.set_number(f64::from(instruction.d()));
499                    }
500                    Opcode::LoadK => {
501                        let ra = base
502                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
503                            .value_unchecked();
504                        let kv = proto.vm_const(constants, instruction.d() as u16 as usize);
505                        ra.set_obj(kv);
506                    }
507                    Opcode::Move => {
508                        let top = thread.stack_top();
509                        let ra = base
510                            .vm_reg_cursor(top, instruction.a() as usize)
511                            .value_unchecked();
512                        let rb = base
513                            .vm_reg_cursor(top, instruction.b() as usize)
514                            .value_unchecked();
515                        ra.set_obj(rb);
516                    }
517                    Opcode::GetGlobal => {
518                        let ra_cursor =
519                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
520                        let ra = ra_cursor.value_unchecked();
521                        let aux = { InstructionAux::new((*pc).word()) };
522                        pc = pc.add(1);
523                        let kv = proto.vm_const(constants, aux.word() as usize);
524                        debug_assert!(kv.is_string());
525
526                        let env = closure.env();
527                        let slot = instruction.c() as usize & env.node_mask_8();
528                        let node = env.node(slot as i32);
529
530                        if node.has_string_key(kv.string_value()) && !node.value_is_nil() {
531                            ra.set_obj(node.value_unchecked());
532                        } else {
533                            let mut global_storage = RAW_TVALUE_NIL;
534                            let global = TValue::from_mut(&mut global_storage);
535                            global.set_table_value(env);
536                            thread.set_cached_slot(slot as i32);
537                            thread.set_vm_saved_pc(pc);
538                            thread.get_table_internal(global, kv, ra_cursor)?;
539                            let cached_slot = thread.cached_slot();
540                            patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
541                            base = thread.stack_base();
542                        }
543                    }
544                    Opcode::SetGlobal => {
545                        let ra = base
546                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
547                            .value_unchecked();
548                        let aux = { InstructionAux::new((*pc).word()) };
549                        pc = pc.add(1);
550                        let kv = proto.vm_const(constants, aux.word() as usize);
551                        debug_assert!(kv.is_string());
552
553                        let env = closure.env();
554                        let slot = instruction.c() as usize & env.node_mask_8();
555                        let node = env.node(slot as i32);
556
557                        if node.has_string_key(kv.string_value()) && !node.value_is_nil() && {
558                            env.as_ptr().as_ref().unwrap_unchecked().readonly == 0
559                        } {
560                            node.value_unchecked().set_obj(ra);
561                            if ra.is_collectable() {
562                                let table_object: GcObject = env.into();
563                                let child = ra.gc_value();
564                                if table_object.is_black() && child.is_white() {
565                                    thread.barrier_table(env, child);
566                                }
567                            }
568                        } else {
569                            let mut global_storage = RAW_TVALUE_NIL;
570                            let global = TValue::from_mut(&mut global_storage);
571                            global.set_table_value(env);
572                            thread.set_cached_slot(slot as i32);
573                            thread.set_vm_saved_pc(pc);
574                            thread.set_table_internal(global, kv, ra)?;
575                            let cached_slot = thread.cached_slot();
576                            patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
577                            base = thread.stack_base();
578                        }
579                    }
580                    Opcode::NewClosure => {
581                        let ra = base
582                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
583                            .value_unchecked();
584                        let child_proto_index = instruction.d() as u16 as usize;
585                        debug_assert!(
586                            child_proto_index
587                                < proto.as_ptr().as_ref().unwrap_unchecked().size_p as usize
588                        );
589                        let child_proto = proto.child_proto(child_proto_index).unwrap_unchecked();
590
591                        thread.set_vm_saved_pc(pc);
592
593                        let env = Some(closure.env());
594                        let new_closure = thread.new_lua_closure(
595                            i32::from(child_proto.as_ptr().as_ref().unwrap_unchecked().n_ups),
596                            env,
597                            child_proto,
598                        )?;
599                        ra.set_closure_value(new_closure);
600
601                        for upvalue_index in
602                            0..child_proto.as_ptr().as_ref().unwrap_unchecked().n_ups as usize
603                        {
604                            let capture_instruction = { *pc };
605                            pc = pc.add(1);
606                            debug_assert_eq!(capture_instruction.opcode(), Opcode::Capture);
607
608                            match capture_instruction.a() {
609                                LCT_VAL => {
610                                    let captured = base
611                                        .vm_reg_cursor(
612                                            thread.stack_top(),
613                                            capture_instruction.b() as usize,
614                                        )
615                                        .value_unchecked();
616                                    new_closure.lua_upvalue_ref(upvalue_index).set_obj(captured);
617                                }
618                                LCT_REF => {
619                                    let captured = base
620                                        .vm_reg_cursor(
621                                            thread.stack_top(),
622                                            capture_instruction.b() as usize,
623                                        )
624                                        .value_unchecked();
625                                    let upvalue = thread.find_upvalue(captured)?;
626                                    new_closure
627                                        .lua_upvalue_ref(upvalue_index)
628                                        .set_upvalue_value(upvalue);
629                                }
630                                LCT_UPVAL => {
631                                    let captured =
632                                        closure.lua_upvalue_ref(capture_instruction.b() as usize);
633                                    new_closure.lua_upvalue_ref(upvalue_index).set_obj(captured);
634                                }
635                                _ => unreachable!("unknown upvalue capture type"),
636                            }
637                        }
638
639                        thread.set_vm_saved_pc(pc);
640                        thread.check_gc()?;
641                        base = thread.stack_base();
642                    }
643                    Opcode::DupClosure => {
644                        let ra = base
645                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
646                            .value_unchecked();
647                        let kv = proto.vm_const(constants, instruction.d() as u16 as usize);
648                        let constant_closure = { kv.closure_value() };
649
650                        thread.set_vm_saved_pc(pc);
651
652                        let env = closure.env();
653                        let mut new_closure = if constant_closure.env() == env {
654                            constant_closure
655                        } else {
656                            let constant_proto = { constant_closure.proto().unwrap_unchecked() };
657                            thread.new_lua_closure(
658                                i32::from(
659                                    constant_closure
660                                        .as_ptr()
661                                        .as_ref()
662                                        .unwrap_unchecked()
663                                        .n_upvalues,
664                                ),
665                                Some(env),
666                                constant_proto,
667                            )?
668                        };
669                        ra.set_closure_value(new_closure);
670
671                        let upvalue_count = {
672                            constant_closure
673                                .as_ptr()
674                                .as_ref()
675                                .unwrap_unchecked()
676                                .n_upvalues as usize
677                        };
678                        let mut upvalue_index = 0usize;
679                        while upvalue_index < upvalue_count {
680                            let capture_instruction = { *pc.add(upvalue_index) };
681                            debug_assert_eq!(capture_instruction.opcode(), Opcode::Capture);
682
683                            debug_assert!(matches!(capture_instruction.a(), LCT_VAL | LCT_UPVAL));
684
685                            let captured = match capture_instruction.a() {
686                                LCT_VAL => base
687                                    .vm_reg_cursor(
688                                        thread.stack_top(),
689                                        capture_instruction.b() as usize,
690                                    )
691                                    .value_unchecked(),
692                                LCT_UPVAL => {
693                                    closure.lua_upvalue_ref(capture_instruction.b() as usize)
694                                }
695                                _ => unreachable!("DUPCLOSURE capture stream must not contain REF"),
696                            };
697
698                            let target = new_closure.lua_upvalue_ref(upvalue_index);
699
700                            if new_closure == constant_closure && target.raw_equal(captured) {
701                                upvalue_index += 1;
702                                continue;
703                            }
704
705                            if new_closure == constant_closure
706                                && constant_closure
707                                    .as_ptr()
708                                    .as_ref()
709                                    .unwrap_unchecked()
710                                    .preload
711                                    == 0
712                            {
713                                let constant_proto = constant_closure.proto().unwrap_unchecked();
714                                new_closure = thread.new_lua_closure(
715                                    i32::from(
716                                        constant_closure
717                                            .as_ptr()
718                                            .as_ref()
719                                            .unwrap_unchecked()
720                                            .n_upvalues,
721                                    ),
722                                    Some(env),
723                                    constant_proto,
724                                )?;
725                                {
726                                    ra.set_closure_value(new_closure);
727                                }
728
729                                upvalue_index = 0;
730                                continue;
731                            }
732
733                            target.set_obj(captured);
734
735                            if captured.is_collectable() {
736                                let object: GcObject = new_closure.into();
737                                let child = captured.gc_value();
738                                if object.is_black() && child.is_white() {
739                                    thread.barrier_forward(object, child);
740                                }
741                            }
742
743                            upvalue_index += 1;
744                        }
745
746                        {
747                            new_closure.as_ptr().as_mut().unwrap_unchecked().preload = 0;
748                        }
749
750                        if constant_closure != new_closure {
751                            thread.set_vm_saved_pc(pc);
752                            thread.check_gc()?;
753                            base = thread.stack_base();
754                        }
755                        pc = pc.add(upvalue_count);
756                    }
757                    Opcode::And => {
758                        let ra = base
759                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
760                            .value_unchecked();
761                        let rb = base
762                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
763                            .value_unchecked();
764                        let rc = base
765                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
766                            .value_unchecked();
767                        let value = if rb.is_false() { rb } else { rc };
768
769                        ra.set_obj(value);
770                    }
771                    Opcode::Or => {
772                        let ra = base
773                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
774                            .value_unchecked();
775                        let rb = base
776                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
777                            .value_unchecked();
778                        let rc = base
779                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
780                            .value_unchecked();
781                        let value = if rb.is_false() { rc } else { rb };
782
783                        ra.set_obj(value);
784                    }
785                    Opcode::AndK => {
786                        let ra = base
787                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
788                            .value_unchecked();
789                        let rb = base
790                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
791                            .value_unchecked();
792                        let kv = proto.vm_const(constants, instruction.c() as usize);
793                        let value = if rb.is_false() { rb } else { kv };
794
795                        ra.set_obj(value);
796                    }
797                    Opcode::OrK => {
798                        let ra = base
799                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
800                            .value_unchecked();
801                        let rb = base
802                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
803                            .value_unchecked();
804                        let kv = proto.vm_const(constants, instruction.c() as usize);
805                        let value = if rb.is_false() { kv } else { rb };
806
807                        ra.set_obj(value);
808                    }
809                    Opcode::Not => {
810                        let ra = base
811                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
812                            .value_unchecked();
813                        let rb = base
814                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
815                            .value_unchecked();
816
817                        {
818                            ra.set_boolean(i32::from(rb.is_false()));
819                        }
820                    }
821                    Opcode::Add => {
822                        let ra_cursor =
823                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
824                        let ra = ra_cursor.value_unchecked();
825                        let rb = base
826                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
827                            .value_unchecked();
828                        let rc = base
829                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
830                            .value_unchecked();
831
832                        if rb.is_number() && rc.is_number() {
833                            {
834                                ra.set_number(rb.number_value() + rc.number_value());
835                            }
836                        } else if rb.is_vector() && rc.is_vector() {
837                            let bx = { rb.vector_ptr() };
838                            let cx = { rc.vector_ptr() };
839                            {
840                                ra.set_vector4(
841                                    *bx + *cx,
842                                    *bx.add(1) + *cx.add(1),
843                                    *bx.add(2) + *cx.add(2),
844                                    vector_w_ptr(bx) + vector_w_ptr(cx),
845                                );
846                            }
847                        } else {
848                            let function = thread.tm_by_obj_or_nil(rb, TmEvent::Add);
849                            if { rb.is_userdata() } && {
850                                function.is_function() && function.is_native_function()
851                            } {
852                                let top_cursor = thread.stack_top();
853                                debug_assert!({
854                                    top_cursor.add(3)
855                                        < thread.stack().add(
856                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
857                                                as usize,
858                                        )
859                                });
860                                {
861                                    top_cursor.value_unchecked().set_obj(function);
862                                    top_cursor.add(1).value_unchecked().set_obj(rb);
863                                    top_cursor.add(2).value_unchecked().set_obj(rc);
864                                    thread.set_stack_top(top_cursor.add(3));
865                                }
866
867                                thread.set_vm_saved_pc(pc);
868                                thread.call_tm(2, i32::from(instruction.a()))?;
869                                base = thread.stack_base();
870                            } else {
871                                thread.set_vm_saved_pc(pc);
872                                thread.do_arith_impl(ra_cursor, rb, rc, TmEvent::Add)?;
873                                base = thread.stack_base();
874                            }
875                        }
876                    }
877                    Opcode::Sub => {
878                        let ra_cursor =
879                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
880                        let ra = ra_cursor.value_unchecked();
881                        let rb = base
882                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
883                            .value_unchecked();
884                        let rc = base
885                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
886                            .value_unchecked();
887
888                        if rb.is_number() && rc.is_number() {
889                            {
890                                ra.set_number(rb.number_value() - rc.number_value());
891                            }
892                        } else if rb.is_vector() && rc.is_vector() {
893                            let bx = { rb.vector_ptr() };
894                            let cx = { rc.vector_ptr() };
895                            {
896                                ra.set_vector4(
897                                    *bx - *cx,
898                                    *bx.add(1) - *cx.add(1),
899                                    *bx.add(2) - *cx.add(2),
900                                    vector_w_ptr(bx) - vector_w_ptr(cx),
901                                );
902                            }
903                        } else {
904                            let function = thread.tm_by_obj_or_nil(rb, TmEvent::Sub);
905                            if { rb.is_userdata() } && {
906                                function.is_function() && function.is_native_function()
907                            } {
908                                let top_cursor = thread.stack_top();
909                                debug_assert!({
910                                    top_cursor.add(3)
911                                        < thread.stack().add(
912                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
913                                                as usize,
914                                        )
915                                });
916                                {
917                                    top_cursor.value_unchecked().set_obj(function);
918                                    top_cursor.add(1).value_unchecked().set_obj(rb);
919                                    top_cursor.add(2).value_unchecked().set_obj(rc);
920                                    thread.set_stack_top(top_cursor.add(3));
921                                }
922
923                                thread.set_vm_saved_pc(pc);
924                                thread.call_tm(2, i32::from(instruction.a()))?;
925                                base = thread.stack_base();
926                            } else {
927                                thread.set_vm_saved_pc(pc);
928                                thread.do_arith_impl(ra_cursor, rb, rc, TmEvent::Sub)?;
929                                base = thread.stack_base();
930                            }
931                        }
932                    }
933                    Opcode::Mul => {
934                        let ra_cursor =
935                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
936                        let ra = ra_cursor.value_unchecked();
937                        let rb = base
938                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
939                            .value_unchecked();
940                        let rc = base
941                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
942                            .value_unchecked();
943
944                        if rb.is_number() && rc.is_number() {
945                            {
946                                ra.set_number(rb.number_value() * rc.number_value());
947                            }
948                        } else if rb.is_vector() && rc.is_number() {
949                            let right = { rc.number_value() as f32 };
950                            let bx = { rb.vector_ptr() };
951                            {
952                                ra.set_vector4(
953                                    *bx * right,
954                                    *bx.add(1) * right,
955                                    *bx.add(2) * right,
956                                    vector_w_ptr(bx) * right,
957                                );
958                            }
959                        } else if rb.is_vector() && rc.is_vector() {
960                            let bx = { rb.vector_ptr() };
961                            let cx = { rc.vector_ptr() };
962                            {
963                                ra.set_vector4(
964                                    *bx * *cx,
965                                    *bx.add(1) * *cx.add(1),
966                                    *bx.add(2) * *cx.add(2),
967                                    vector_w_ptr(bx) * vector_w_ptr(cx),
968                                );
969                            }
970                        } else if rb.is_number() && rc.is_vector() {
971                            let left = { rb.number_value() as f32 };
972                            let cx = { rc.vector_ptr() };
973                            {
974                                ra.set_vector4(
975                                    left * *cx,
976                                    left * *cx.add(1),
977                                    left * *cx.add(2),
978                                    left * vector_w_ptr(cx),
979                                );
980                            }
981                        } else {
982                            let tm_operand = if rb.is_number() { rc } else { rb };
983                            let function = thread.tm_by_obj_or_nil(tm_operand, TmEvent::Mul);
984                            if { tm_operand.is_userdata() } && {
985                                function.is_function() && function.is_native_function()
986                            } {
987                                let top_cursor = thread.stack_top();
988                                debug_assert!({
989                                    top_cursor.add(3)
990                                        < thread.stack().add(
991                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
992                                                as usize,
993                                        )
994                                });
995                                {
996                                    top_cursor.value_unchecked().set_obj(function);
997                                    top_cursor.add(1).value_unchecked().set_obj(rb);
998                                    top_cursor.add(2).value_unchecked().set_obj(rc);
999                                    thread.set_stack_top(top_cursor.add(3));
1000                                }
1001
1002                                thread.set_vm_saved_pc(pc);
1003                                thread.call_tm(2, i32::from(instruction.a()))?;
1004                                base = thread.stack_base();
1005                            } else {
1006                                thread.set_vm_saved_pc(pc);
1007                                thread.do_arith_impl(ra_cursor, rb, rc, TmEvent::Mul)?;
1008                                base = thread.stack_base();
1009                            }
1010                        }
1011                    }
1012                    Opcode::Div => {
1013                        let ra_cursor =
1014                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1015                        let ra = ra_cursor.value_unchecked();
1016                        let rb = base
1017                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1018                            .value_unchecked();
1019                        let rc = base
1020                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
1021                            .value_unchecked();
1022
1023                        if rb.is_number() && rc.is_number() {
1024                            {
1025                                ra.set_number(rb.number_value() / rc.number_value());
1026                            }
1027                        } else if rb.is_vector() && rc.is_number() {
1028                            let right = { rc.number_value() as f32 };
1029                            let bx = { rb.vector_ptr() };
1030                            {
1031                                ra.set_vector4(
1032                                    *bx / right,
1033                                    *bx.add(1) / right,
1034                                    *bx.add(2) / right,
1035                                    vector_w_ptr(bx) / right,
1036                                );
1037                            }
1038                        } else if rb.is_vector() && rc.is_vector() {
1039                            let bx = { rb.vector_ptr() };
1040                            let cx = { rc.vector_ptr() };
1041                            {
1042                                ra.set_vector4(
1043                                    *bx / *cx,
1044                                    *bx.add(1) / *cx.add(1),
1045                                    *bx.add(2) / *cx.add(2),
1046                                    vector_w_ptr(bx) / vector_w_ptr(cx),
1047                                );
1048                            }
1049                        } else if rb.is_number() && rc.is_vector() {
1050                            let left = { rb.number_value() as f32 };
1051                            let cx = { rc.vector_ptr() };
1052                            {
1053                                ra.set_vector4(
1054                                    left / *cx,
1055                                    left / *cx.add(1),
1056                                    left / *cx.add(2),
1057                                    left / vector_w_ptr(cx),
1058                                );
1059                            }
1060                        } else {
1061                            let tm_operand = if rb.is_number() { rc } else { rb };
1062                            let function = thread.tm_by_obj_or_nil(tm_operand, TmEvent::Div);
1063                            if { tm_operand.is_userdata() } && {
1064                                function.is_function() && function.is_native_function()
1065                            } {
1066                                let top_cursor = thread.stack_top();
1067                                debug_assert!({
1068                                    top_cursor.add(3)
1069                                        < thread.stack().add(
1070                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
1071                                                as usize,
1072                                        )
1073                                });
1074                                {
1075                                    top_cursor.value_unchecked().set_obj(function);
1076                                    top_cursor.add(1).value_unchecked().set_obj(rb);
1077                                    top_cursor.add(2).value_unchecked().set_obj(rc);
1078                                    thread.set_stack_top(top_cursor.add(3));
1079                                }
1080
1081                                thread.set_vm_saved_pc(pc);
1082                                thread.call_tm(2, i32::from(instruction.a()))?;
1083                                base = thread.stack_base();
1084                            } else {
1085                                thread.set_vm_saved_pc(pc);
1086                                thread.do_arith_impl(ra_cursor, rb, rc, TmEvent::Div)?;
1087                                base = thread.stack_base();
1088                            }
1089                        }
1090                    }
1091                    Opcode::IDiv => {
1092                        let ra_cursor =
1093                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1094                        let ra = ra_cursor.value_unchecked();
1095                        let rb = base
1096                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1097                            .value_unchecked();
1098                        let rc = base
1099                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
1100                            .value_unchecked();
1101
1102                        if rb.is_number() && rc.is_number() {
1103                            {
1104                                ra.set_number(crate::number::num_idiv(
1105                                    rb.number_value(),
1106                                    rc.number_value(),
1107                                ));
1108                            }
1109                        } else if rb.is_vector() && rc.is_number() {
1110                            let right = { rc.number_value() as f32 };
1111                            let bx = { rb.vector_ptr() };
1112                            {
1113                                ra.set_vector4(
1114                                    crate::number::num_idiv((*bx) as f64, right as f64) as f32,
1115                                    crate::number::num_idiv((*bx.add(1)) as f64, right as f64)
1116                                        as f32,
1117                                    crate::number::num_idiv((*bx.add(2)) as f64, right as f64)
1118                                        as f32,
1119                                    crate::number::num_idiv(vector_w_ptr(bx) as f64, right as f64)
1120                                        as f32,
1121                                );
1122                            }
1123                        } else {
1124                            let tm_operand = if rb.is_number() { rc } else { rb };
1125                            let function = thread.tm_by_obj_or_nil(tm_operand, TmEvent::IDiv);
1126                            if { tm_operand.is_userdata() } && {
1127                                function.is_function() && function.is_native_function()
1128                            } {
1129                                let top_cursor = thread.stack_top();
1130                                debug_assert!({
1131                                    top_cursor.add(3)
1132                                        < thread.stack().add(
1133                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
1134                                                as usize,
1135                                        )
1136                                });
1137                                {
1138                                    top_cursor.value_unchecked().set_obj(function);
1139                                    top_cursor.add(1).value_unchecked().set_obj(rb);
1140                                    top_cursor.add(2).value_unchecked().set_obj(rc);
1141                                    thread.set_stack_top(top_cursor.add(3));
1142                                }
1143
1144                                thread.set_vm_saved_pc(pc);
1145                                thread.call_tm(2, i32::from(instruction.a()))?;
1146                                base = thread.stack_base();
1147                            } else {
1148                                thread.set_vm_saved_pc(pc);
1149                                thread.do_arith_impl(ra_cursor, rb, rc, TmEvent::IDiv)?;
1150                                base = thread.stack_base();
1151                            }
1152                        }
1153                    }
1154                    Opcode::Mod => {
1155                        let ra_cursor =
1156                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1157                        let ra = ra_cursor.value_unchecked();
1158                        let rb = base
1159                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1160                            .value_unchecked();
1161                        let rc = base
1162                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
1163                            .value_unchecked();
1164
1165                        if rb.is_number() && rc.is_number() {
1166                            {
1167                                ra.set_number(crate::number::num_mod(
1168                                    rb.number_value(),
1169                                    rc.number_value(),
1170                                ));
1171                            }
1172                        } else {
1173                            thread.set_vm_saved_pc(pc);
1174                            thread.do_arith_impl(ra_cursor, rb, rc, TmEvent::Mod)?;
1175                            base = thread.stack_base();
1176                        }
1177                    }
1178                    Opcode::Pow => {
1179                        let ra_cursor =
1180                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1181                        let ra = ra_cursor.value_unchecked();
1182                        let rb = base
1183                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1184                            .value_unchecked();
1185                        let rc = base
1186                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
1187                            .value_unchecked();
1188
1189                        if rb.is_number() && rc.is_number() {
1190                            {
1191                                ra.set_number(rb.number_value().powf(rc.number_value()));
1192                            }
1193                        } else {
1194                            thread.set_vm_saved_pc(pc);
1195                            thread.do_arith_impl(ra_cursor, rb, rc, TmEvent::Pow)?;
1196                            base = thread.stack_base();
1197                        }
1198                    }
1199                    Opcode::AddK => {
1200                        let ra_cursor =
1201                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1202                        let ra = ra_cursor.value_unchecked();
1203                        let rb = base
1204                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1205                            .value_unchecked();
1206                        let kv = proto.vm_const(constants, instruction.c() as usize);
1207
1208                        if rb.is_number() {
1209                            {
1210                                ra.set_number(rb.number_value() + kv.number_value());
1211                            }
1212                        } else {
1213                            thread.set_vm_saved_pc(pc);
1214                            thread.do_arith_impl(ra_cursor, rb, kv, TmEvent::Add)?;
1215                            base = thread.stack_base();
1216                        }
1217                    }
1218                    Opcode::SubK => {
1219                        let ra_cursor =
1220                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1221                        let ra = ra_cursor.value_unchecked();
1222                        let rb = base
1223                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1224                            .value_unchecked();
1225                        let kv = proto.vm_const(constants, instruction.c() as usize);
1226
1227                        if rb.is_number() {
1228                            {
1229                                ra.set_number(rb.number_value() - kv.number_value());
1230                            }
1231                        } else {
1232                            thread.set_vm_saved_pc(pc);
1233                            thread.do_arith_impl(ra_cursor, rb, kv, TmEvent::Sub)?;
1234                            base = thread.stack_base();
1235                        }
1236                    }
1237                    Opcode::MulK => {
1238                        let ra_cursor =
1239                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1240                        let ra = ra_cursor.value_unchecked();
1241                        let rb = base
1242                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1243                            .value_unchecked();
1244                        let kv = proto.vm_const(constants, instruction.c() as usize);
1245
1246                        if rb.is_number() {
1247                            {
1248                                ra.set_number(rb.number_value() * kv.number_value());
1249                            }
1250                        } else if rb.is_vector() {
1251                            let right = { kv.number_value() as f32 };
1252                            let bx = { rb.vector_ptr() };
1253                            {
1254                                ra.set_vector4(
1255                                    *bx * right,
1256                                    *bx.add(1) * right,
1257                                    *bx.add(2) * right,
1258                                    vector_w_ptr(bx) * right,
1259                                );
1260                            }
1261                        } else {
1262                            let function = thread.tm_by_obj_or_nil(rb, TmEvent::Mul);
1263                            if { rb.is_userdata() } && {
1264                                function.is_function() && function.is_native_function()
1265                            } {
1266                                let top_cursor = thread.stack_top();
1267                                debug_assert!({
1268                                    top_cursor.add(3)
1269                                        < thread.stack().add(
1270                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
1271                                                as usize,
1272                                        )
1273                                });
1274                                {
1275                                    top_cursor.value_unchecked().set_obj(function);
1276                                    top_cursor.add(1).value_unchecked().set_obj(rb);
1277                                    top_cursor.add(2).value_unchecked().set_obj(kv);
1278                                    thread.set_stack_top(top_cursor.add(3));
1279                                }
1280
1281                                thread.set_vm_saved_pc(pc);
1282                                thread.call_tm(2, i32::from(instruction.a()))?;
1283                                base = thread.stack_base();
1284                            } else {
1285                                thread.set_vm_saved_pc(pc);
1286                                thread.do_arith_impl(ra_cursor, rb, kv, TmEvent::Mul)?;
1287                                base = thread.stack_base();
1288                            }
1289                        }
1290                    }
1291                    Opcode::DivK => {
1292                        let ra_cursor =
1293                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1294                        let ra = ra_cursor.value_unchecked();
1295                        let rb = base
1296                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1297                            .value_unchecked();
1298                        let kv = proto.vm_const(constants, instruction.c() as usize);
1299
1300                        if rb.is_number() {
1301                            {
1302                                ra.set_number(rb.number_value() / kv.number_value());
1303                            }
1304                        } else if rb.is_vector() {
1305                            let right = { kv.number_value() as f32 };
1306                            let bx = { rb.vector_ptr() };
1307                            {
1308                                ra.set_vector4(
1309                                    *bx / right,
1310                                    *bx.add(1) / right,
1311                                    *bx.add(2) / right,
1312                                    vector_w_ptr(bx) / right,
1313                                );
1314                            }
1315                        } else {
1316                            let function = thread.tm_by_obj_or_nil(rb, TmEvent::Div);
1317                            if { rb.is_userdata() } && {
1318                                function.is_function() && function.is_native_function()
1319                            } {
1320                                let top_cursor = thread.stack_top();
1321                                debug_assert!({
1322                                    top_cursor.add(3)
1323                                        < thread.stack().add(
1324                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
1325                                                as usize,
1326                                        )
1327                                });
1328                                {
1329                                    top_cursor.value_unchecked().set_obj(function);
1330                                    top_cursor.add(1).value_unchecked().set_obj(rb);
1331                                    top_cursor.add(2).value_unchecked().set_obj(kv);
1332                                    thread.set_stack_top(top_cursor.add(3));
1333                                }
1334
1335                                thread.set_vm_saved_pc(pc);
1336                                thread.call_tm(2, i32::from(instruction.a()))?;
1337                                base = thread.stack_base();
1338                            } else {
1339                                thread.set_vm_saved_pc(pc);
1340                                thread.do_arith_impl(ra_cursor, rb, kv, TmEvent::Div)?;
1341                                base = thread.stack_base();
1342                            }
1343                        }
1344                    }
1345                    Opcode::IDivK => {
1346                        let ra_cursor =
1347                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1348                        let ra = ra_cursor.value_unchecked();
1349                        let rb = base
1350                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1351                            .value_unchecked();
1352                        let kv = proto.vm_const(constants, instruction.c() as usize);
1353
1354                        if rb.is_number() {
1355                            {
1356                                ra.set_number(crate::number::num_idiv(
1357                                    rb.number_value(),
1358                                    kv.number_value(),
1359                                ));
1360                            }
1361                        } else if rb.is_vector() {
1362                            let right = { kv.number_value() as f32 };
1363                            let bx = { rb.vector_ptr() };
1364                            {
1365                                ra.set_vector4(
1366                                    crate::number::num_idiv((*bx) as f64, right as f64) as f32,
1367                                    crate::number::num_idiv((*bx.add(1)) as f64, right as f64)
1368                                        as f32,
1369                                    crate::number::num_idiv((*bx.add(2)) as f64, right as f64)
1370                                        as f32,
1371                                    crate::number::num_idiv(vector_w_ptr(bx) as f64, right as f64)
1372                                        as f32,
1373                                );
1374                            }
1375                        } else {
1376                            let function = thread.tm_by_obj_or_nil(rb, TmEvent::IDiv);
1377                            if { rb.is_userdata() } && {
1378                                function.is_function() && function.is_native_function()
1379                            } {
1380                                let top_cursor = thread.stack_top();
1381                                debug_assert!({
1382                                    top_cursor.add(3)
1383                                        < thread.stack().add(
1384                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
1385                                                as usize,
1386                                        )
1387                                });
1388                                {
1389                                    top_cursor.value_unchecked().set_obj(function);
1390                                    top_cursor.add(1).value_unchecked().set_obj(rb);
1391                                    top_cursor.add(2).value_unchecked().set_obj(kv);
1392                                    thread.set_stack_top(top_cursor.add(3));
1393                                }
1394
1395                                thread.set_vm_saved_pc(pc);
1396                                thread.call_tm(2, i32::from(instruction.a()))?;
1397                                base = thread.stack_base();
1398                            } else {
1399                                thread.set_vm_saved_pc(pc);
1400                                thread.do_arith_impl(ra_cursor, rb, kv, TmEvent::IDiv)?;
1401                                base = thread.stack_base();
1402                            }
1403                        }
1404                    }
1405                    Opcode::ModK => {
1406                        let ra_cursor =
1407                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1408                        let ra = ra_cursor.value_unchecked();
1409                        let rb = base
1410                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1411                            .value_unchecked();
1412                        let kv = proto.vm_const(constants, instruction.c() as usize);
1413
1414                        if rb.is_number() {
1415                            {
1416                                ra.set_number(crate::number::num_mod(
1417                                    rb.number_value(),
1418                                    kv.number_value(),
1419                                ));
1420                            }
1421                        } else {
1422                            thread.set_vm_saved_pc(pc);
1423                            thread.do_arith_impl(ra_cursor, rb, kv, TmEvent::Mod)?;
1424                            base = thread.stack_base();
1425                        }
1426                    }
1427                    Opcode::PowK => {
1428                        let ra_cursor =
1429                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1430                        let ra = ra_cursor.value_unchecked();
1431                        let rb = base
1432                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1433                            .value_unchecked();
1434                        let kv = proto.vm_const(constants, instruction.c() as usize);
1435
1436                        if rb.is_number() {
1437                            let left = { rb.number_value() };
1438                            let right = { kv.number_value() };
1439                            let result = if right == 2.0 {
1440                                left * left
1441                            } else if right == 0.5 {
1442                                left.sqrt()
1443                            } else if right == 3.0 {
1444                                left * left * left
1445                            } else {
1446                                left.powf(right)
1447                            };
1448
1449                            {
1450                                ra.set_number(result);
1451                            }
1452                        } else {
1453                            thread.set_vm_saved_pc(pc);
1454                            thread.do_arith_impl(ra_cursor, rb, kv, TmEvent::Pow)?;
1455                            base = thread.stack_base();
1456                        }
1457                    }
1458                    Opcode::Concat => {
1459                        let b = instruction.b() as i32;
1460                        let c = instruction.c() as i32;
1461
1462                        thread.set_vm_saved_pc(pc);
1463                        thread.concat_internal(c - b + 1, c)?;
1464                        base = thread.stack_base();
1465
1466                        let ra = base
1467                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1468                            .value_unchecked();
1469                        ra.set_obj(base.add(b as usize).value_unchecked());
1470
1471                        thread.set_vm_saved_pc(pc);
1472                        thread.check_gc()?;
1473                        base = thread.stack_base();
1474                    }
1475                    Opcode::Minus => {
1476                        let ra_cursor =
1477                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1478                        let ra = ra_cursor.value_unchecked();
1479                        let rb = base
1480                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1481                            .value_unchecked();
1482
1483                        if rb.is_number() {
1484                            {
1485                                ra.set_number(-rb.number_value());
1486                            }
1487                        } else if rb.is_vector() {
1488                            let bx = { rb.vector_ptr() };
1489                            {
1490                                ra.set_vector4(-*bx, -*bx.add(1), -*bx.add(2), -vector_w_ptr(bx));
1491                            }
1492                        } else {
1493                            let function = thread.tm_by_obj_or_nil(rb, TmEvent::Unm);
1494                            if { rb.is_userdata() } && {
1495                                function.is_function() && function.is_native_function()
1496                            } {
1497                                let top_cursor = thread.stack_top();
1498                                debug_assert!({
1499                                    top_cursor.add(2)
1500                                        < thread.stack().add(
1501                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
1502                                                as usize,
1503                                        )
1504                                });
1505                                {
1506                                    top_cursor.value_unchecked().set_obj(function);
1507                                    top_cursor.add(1).value_unchecked().set_obj(rb);
1508                                    thread.set_stack_top(top_cursor.add(2));
1509                                }
1510
1511                                thread.set_vm_saved_pc(pc);
1512                                thread.call_tm(1, i32::from(instruction.a()))?;
1513                                base = thread.stack_base();
1514                            } else {
1515                                thread.set_vm_saved_pc(pc);
1516                                thread.do_arith_impl(ra_cursor, rb, rb, TmEvent::Unm)?;
1517                                base = thread.stack_base();
1518                            }
1519                        }
1520                    }
1521                    Opcode::Length => {
1522                        let ra_cursor =
1523                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1524                        let ra = ra_cursor.value_unchecked();
1525                        let rb = base
1526                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
1527                            .value_unchecked();
1528
1529                        if rb.is_table() {
1530                            let table = { rb.table_value() };
1531                            if thread.fast_notm(table.metatable(), TmEvent::Len) {
1532                                {
1533                                    ra.set_number(table.getn() as f64);
1534                                }
1535                            } else {
1536                                thread.set_vm_saved_pc(pc);
1537                                thread.do_len(ra_cursor, rb)?;
1538                                base = thread.stack_base();
1539                            }
1540                        } else if rb.is_string() {
1541                            {
1542                                ra.set_number(
1543                                    rb.string_value().as_ptr().as_ref().unwrap_unchecked().len
1544                                        as f64,
1545                                );
1546                            }
1547                        } else {
1548                            thread.set_vm_saved_pc(pc);
1549                            thread.do_len(ra_cursor, rb)?;
1550                            base = thread.stack_base();
1551                        }
1552                    }
1553                    Opcode::NewTable => {
1554                        let ra = base
1555                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1556                            .value_unchecked();
1557                        let b = instruction.b();
1558                        let aux = { InstructionAux::new((*pc).word()) };
1559                        pc = pc.add(1);
1560
1561                        thread.set_vm_saved_pc(pc);
1562                        let table = thread.new_table_internal(
1563                            aux.word() as i32,
1564                            if b == 0 {
1565                                0
1566                            } else {
1567                                1i32 << (i32::from(b) - 1)
1568                            },
1569                        )?;
1570                        {
1571                            ra.set_table_value(table);
1572                        }
1573                        thread.check_gc()?;
1574                        base = thread.stack_base();
1575                    }
1576                    Opcode::DupTable => {
1577                        let ra = base
1578                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1579                            .value_unchecked();
1580                        let kv = proto.vm_const(constants, instruction.d() as u16 as usize);
1581                        debug_assert!({ kv.is_table() });
1582
1583                        thread.set_vm_saved_pc(pc);
1584                        let table = thread.clone_table_internal(kv.table_value())?;
1585                        {
1586                            ra.set_table_value(table);
1587                        }
1588                        thread.check_gc()?;
1589                        base = thread.stack_base();
1590                    }
1591                    Opcode::SetList => {
1592                        let ra = base
1593                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1594                            .value_unchecked();
1595                        let rb = { base.add(instruction.b() as usize) };
1596                        let mut c = i32::from(instruction.c()) - 1;
1597                        let index = { InstructionAux::new((*pc).word()).word() as i32 };
1598                        pc = pc.add(1);
1599
1600                        if c == LUA_MULTRET {
1601                            c = thread.stack_top().offset_from(rb) as i32;
1602                            {
1603                                thread.set_stack_top(thread.current_call_info().top());
1604                            }
1605                        }
1606
1607                        if !ra.is_table() {
1608                            return Ok(());
1609                        }
1610
1611                        let table = { ra.table_value() };
1612                        let last = index + c - 1;
1613                        if last > { table.as_ptr().as_ref().unwrap_unchecked().size_array } {
1614                            thread.set_vm_saved_pc(pc);
1615                            thread.resize_array(table, last)?;
1616                            base = thread.stack_base();
1617                        }
1618
1619                        let array = table.array_cursor();
1620                        let index = index as usize - 1;
1621                        for offset in 0..c as usize {
1622                            array
1623                                .add(index + offset)
1624                                .value_unchecked()
1625                                .set_obj(rb.add(offset).value_unchecked());
1626                        }
1627
1628                        let table_object: GcObject = table.into();
1629                        if table_object.is_black() {
1630                            let table_ref = table.as_ptr().as_mut().unwrap_unchecked();
1631                            thread.barrier_back(table_object, &raw mut table_ref.gc_list);
1632                        }
1633                    }
1634                    Opcode::SubRK => {
1635                        let ra_cursor =
1636                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1637                        let ra = ra_cursor.value_unchecked();
1638                        let kv = proto.vm_const(constants, instruction.b() as usize);
1639                        let rc = base
1640                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
1641                            .value_unchecked();
1642
1643                        if rc.is_number() {
1644                            {
1645                                ra.set_number(kv.number_value() - rc.number_value());
1646                            }
1647                        } else {
1648                            thread.set_vm_saved_pc(pc);
1649                            thread.do_arith_impl(ra_cursor, kv, rc, TmEvent::Sub)?;
1650                            base = thread.stack_base();
1651                        }
1652                    }
1653                    Opcode::DivRK => {
1654                        let ra_cursor =
1655                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1656                        let ra = ra_cursor.value_unchecked();
1657                        let kv = proto.vm_const(constants, instruction.b() as usize);
1658                        let rc = base
1659                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
1660                            .value_unchecked();
1661
1662                        if rc.is_number() {
1663                            {
1664                                ra.set_number(kv.number_value() / rc.number_value());
1665                            }
1666                        } else if rc.is_vector() {
1667                            let left = { kv.number_value() as f32 };
1668                            let cx = { rc.vector_ptr() };
1669                            {
1670                                ra.set_vector4(
1671                                    left / *cx,
1672                                    left / *cx.add(1),
1673                                    left / *cx.add(2),
1674                                    left / vector_w_ptr(cx),
1675                                );
1676                            }
1677                        } else {
1678                            thread.set_vm_saved_pc(pc);
1679                            thread.do_arith_impl(ra_cursor, kv, rc, TmEvent::Div)?;
1680                            base = thread.stack_base();
1681                        }
1682                    }
1683                    Opcode::GetUpval => {
1684                        let ra = base
1685                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1686                            .value_unchecked();
1687                        let upref = closure.lua_upvalue_ref(instruction.b() as usize);
1688                        let value = if upref.is_upvalue() {
1689                            upref.upvalue_value().value()
1690                        } else {
1691                            upref
1692                        };
1693
1694                        ra.set_obj(value);
1695                    }
1696                    Opcode::SetUpval => {
1697                        let ra = base
1698                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1699                            .value_unchecked();
1700                        let upref = closure.lua_upvalue_ref(instruction.b() as usize);
1701                        debug_assert!(upref.is_upvalue());
1702                        let upval = upref.upvalue_value();
1703
1704                        upval.value().set_obj(ra);
1705
1706                        let value = { ra };
1707                        if value.is_collectable() {
1708                            let object: GcObject = upval.into();
1709                            let child = value.gc_value();
1710                            if object.is_black() && child.is_white() {
1711                                thread.barrier_forward(object, child);
1712                            }
1713                        }
1714                    }
1715                    Opcode::CloseUpvals => {
1716                        let ra = base
1717                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1718                            .value_unchecked();
1719                        if let Some(open_upval) = thread.open_upvalue()
1720                            && { open_upval.value_ptr() >= ra.as_ptr() }
1721                        {
1722                            thread.close(ra);
1723                        }
1724                    }
1725                    Opcode::ForNPrep => {
1726                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1727                        let limit = ra;
1728                        let step = { ra.add(1) };
1729                        let index = { ra.add(2) };
1730
1731                        let non_numeric = {
1732                            !limit.value_unchecked().is_number()
1733                                || !step.value_unchecked().is_number()
1734                                || !index.value_unchecked().is_number()
1735                        };
1736                        if non_numeric {
1737                            thread.set_vm_saved_pc(pc);
1738                            thread.prepare_forn(limit, step, index)?;
1739                        }
1740
1741                        let limit_value = { limit.value_unchecked().number_value() };
1742                        let step_value = { step.value_unchecked().number_value() };
1743                        let index_value = { index.value_unchecked().number_value() };
1744
1745                        if !(if step_value > 0.0 {
1746                            index_value <= limit_value
1747                        } else {
1748                            limit_value <= index_value
1749                        }) {
1750                            pc = pc.offset(i32::from(instruction.d()) as isize);
1751                        }
1752                        proto.assert_vm_pc(pc);
1753                    }
1754                    Opcode::ForNLoop => {
1755                        thread.interrupt_vm(insn_pc)?;
1756                        base = thread.stack_base();
1757                        if flags::LuauBackedgeHeapCheck.get() && thread.needs_gc() {
1758                            thread.set_vm_saved_pc(pc);
1759                            thread.step(true)?;
1760                            base = thread.stack_base();
1761                        }
1762
1763                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1764                        let limit = ra;
1765                        let step = { ra.add(1) };
1766                        let index = { ra.add(2) };
1767                        debug_assert!(
1768                            limit.value_unchecked().is_number()
1769                                && step.value_unchecked().is_number()
1770                                && index.value_unchecked().is_number()
1771                        );
1772
1773                        let limit_value = { limit.value_unchecked().number_value() };
1774                        let step_value = { step.value_unchecked().number_value() };
1775                        let next_index = { index.value_unchecked().number_value() } + step_value;
1776
1777                        index.value_unchecked().set_number(next_index);
1778
1779                        if if step_value > 0.0 {
1780                            next_index <= limit_value
1781                        } else {
1782                            limit_value <= next_index
1783                        } {
1784                            pc = pc.offset(i32::from(instruction.d()) as isize);
1785                            proto.assert_vm_pc(pc);
1786                        }
1787                    }
1788                    Opcode::ForGPrep => {
1789                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1790                        let ra_value = ra.value_unchecked();
1791
1792                        if !{ ra_value.is_function() } {
1793                            let metatable = if ra_value.is_table() {
1794                                ra_value.table_value().metatable()
1795                            } else if ra_value.is_userdata() {
1796                                ra_value.userdata_value().metatable()
1797                            } else {
1798                                None
1799                            };
1800
1801                            let iter = if flags::DebugLuauUserDefinedClassesRuntime.get() {
1802                                if let Some(function) = thread.fast_tm(metatable, TmEvent::Iter) {
1803                                    Some(function)
1804                                } else if ra_value.is_object() {
1805                                    let function = thread.tm_by_obj_or_nil(ra_value, TmEvent::Iter);
1806                                    if function.is_nil() {
1807                                        thread.set_vm_saved_pc(pc);
1808                                        return thread
1809                                            .type_error(ra_value, "iterate over")
1810                                            .map_err(Into::into);
1811                                    }
1812                                    Some(function)
1813                                } else if thread.fast_tm(metatable, TmEvent::Call).is_some() {
1814                                    None
1815                                } else if ra_value.is_table() {
1816                                    ra.add(1).value_unchecked().set_obj(ra_value);
1817                                    ra.add(2).value_unchecked().set_light_userdata(
1818                                        ptr::null_mut(),
1819                                        USERDATA_TAG_LIMIT as i32,
1820                                    );
1821                                    ra_value.set_nil();
1822                                    None
1823                                } else {
1824                                    thread.set_vm_saved_pc(pc);
1825                                    return thread
1826                                        .type_error(ra_value, "iterate over")
1827                                        .map_err(Into::into);
1828                                }
1829                            } else if let Some(function) = thread.fast_tm(metatable, TmEvent::Iter)
1830                            {
1831                                Some(function)
1832                            } else if thread.fast_tm(metatable, TmEvent::Call).is_some() {
1833                                None
1834                            } else if ra_value.is_table() {
1835                                ra.add(1).value_unchecked().set_obj(ra_value);
1836                                ra.add(2)
1837                                    .value_unchecked()
1838                                    .set_light_userdata(ptr::null_mut(), USERDATA_TAG_LIMIT as i32);
1839                                ra_value.set_nil();
1840                                None
1841                            } else {
1842                                thread.set_vm_saved_pc(pc);
1843                                return thread
1844                                    .type_error(ra_value, "iterate over")
1845                                    .map_err(Into::into);
1846                            };
1847
1848                            if let Some(function) = iter {
1849                                ra.add(1).value_unchecked().set_obj(ra_value);
1850                                ra_value.set_obj(function);
1851                                thread.set_stack_top(ra.add(2));
1852                                debug_assert!({
1853                                    thread.stack_top()
1854                                        <= thread.stack().add(
1855                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
1856                                                as usize,
1857                                        )
1858                                });
1859
1860                                thread.set_vm_saved_pc(pc);
1861                                thread.call_no_yield(ra, 3)?;
1862                                {
1863                                    thread.set_stack_top(thread.current_call_info().top());
1864                                }
1865
1866                                base = thread.stack_base();
1867                                let ra = base
1868                                    .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
1869                                    .value_unchecked();
1870                                if ra.is_nil() {
1871                                    thread.set_vm_saved_pc(pc);
1872                                    return thread.type_error(ra, "call").map_err(Into::into);
1873                                }
1874                            }
1875                        }
1876
1877                        pc = insn_pc.add(1).offset(i32::from(instruction.d()) as isize);
1878                        proto.assert_vm_pc(pc);
1879                    }
1880                    Opcode::ForGLoop => {
1881                        thread.interrupt_vm(insn_pc)?;
1882                        base = thread.stack_base();
1883                        if flags::LuauBackedgeHeapCheck.get() && thread.needs_gc() {
1884                            thread.set_vm_saved_pc(pc);
1885                            thread.step(true)?;
1886                            base = thread.stack_base();
1887                        }
1888
1889                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1890                        let ra_value = ra.value_unchecked();
1891                        let aux_pc = { insn_pc.add(1) };
1892                        let aux = { (*aux_pc).word() };
1893
1894                        if ra_value.is_nil() && ra.add(1).value_unchecked().is_table() {
1895                            let table = { ra.add(1).value_unchecked().table_value() };
1896                            let mut index =
1897                                { ra.add(2).value_unchecked().pointer_value() as usize as i32 };
1898                            let size_array =
1899                                { table.as_ptr().as_ref().unwrap_unchecked().size_array };
1900                            let aux_signed = aux as i32;
1901                            if aux_signed > 2 {
1902                                for offset in 2..aux_signed as usize {
1903                                    ra.add(3 + offset).value_unchecked().set_nil();
1904                                }
1905                            }
1906
1907                            if aux_signed < 0
1908                                && ((index as u32) >= size_array as u32 || {
1909                                    table.array_slot(index as usize).is_nil()
1910                                })
1911                            {
1912                                pc = aux_pc.add(1);
1913                                proto.assert_vm_pc(pc);
1914                                continue 'vm;
1915                            }
1916
1917                            while (index as u32) < size_array as u32 {
1918                                let value = table.array_slot(index as usize);
1919                                if !value.is_nil() {
1920                                    ra.add(2).value_unchecked().set_light_userdata(
1921                                        (index as usize + 1) as *mut (),
1922                                        USERDATA_TAG_LIMIT as i32,
1923                                    );
1924                                    ra.add(3).value_unchecked().set_number((index + 1) as f64);
1925                                    ra.add(4).value_unchecked().set_obj(value);
1926
1927                                    pc = aux_pc.offset(i32::from(instruction.d()) as isize);
1928                                    proto.assert_vm_pc(pc);
1929                                    break 'dispatch;
1930                                }
1931
1932                                index += 1;
1933                            }
1934
1935                            let size_node = { table.node_count() as i32 };
1936                            while ((index - size_array) as u32) < size_node as u32 {
1937                                let node = table.node(index - size_array);
1938                                if !node.value_unchecked().is_nil() {
1939                                    ra.add(2).value_unchecked().set_light_userdata(
1940                                        (index as usize + 1) as *mut (),
1941                                        USERDATA_TAG_LIMIT as i32,
1942                                    );
1943                                    node.write_key_to_value(ra.add(3).value_unchecked());
1944                                    ra.add(4).value_unchecked().set_obj(node.value_unchecked());
1945
1946                                    pc = aux_pc.offset(i32::from(instruction.d()) as isize);
1947                                    proto.assert_vm_pc(pc);
1948                                    break 'dispatch;
1949                                }
1950
1951                                index += 1;
1952                            }
1953
1954                            pc = aux_pc.add(1);
1955                            proto.assert_vm_pc(pc);
1956                            break 'dispatch;
1957                        }
1958
1959                        ra.add(5)
1960                            .value_unchecked()
1961                            .set_obj(ra.add(2).value_unchecked());
1962                        ra.add(4)
1963                            .value_unchecked()
1964                            .set_obj(ra.add(1).value_unchecked());
1965                        ra.add(3).value_unchecked().set_obj(ra_value);
1966                        thread.set_stack_top(ra.add(6));
1967                        debug_assert!(
1968                            thread.stack_top()
1969                                <= thread.stack().add(
1970                                    thread.as_ptr().as_ref().unwrap_unchecked().stack_size as usize
1971                                )
1972                        );
1973
1974                        thread.set_vm_saved_pc(aux_pc);
1975                        if flags::LuauYieldIter2.get() {
1976                            thread.perform_cally(ra.add(3), i32::from(aux as u8))?;
1977                        } else {
1978                            thread.call_no_yield(ra.add(3), i32::from(aux as u8))?;
1979                        }
1980                        thread.set_stack_top(thread.current_call_info().top());
1981
1982                        base = thread.stack_base();
1983                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1984                        ra.add(2)
1985                            .value_unchecked()
1986                            .set_obj(ra.add(3).value_unchecked());
1987
1988                        pc = if ra.add(3).value_unchecked().is_nil() {
1989                            aux_pc.add(1)
1990                        } else {
1991                            aux_pc.offset(i32::from(instruction.d()) as isize)
1992                        };
1993                        proto.assert_vm_pc(pc);
1994                    }
1995                    Opcode::ForGPrepInext => {
1996                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
1997                        let ra_value = ra.value_unchecked();
1998                        let env = closure.env();
1999
2000                        if { env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0 }
2001                            && { ra.add(1).value_unchecked().is_table() }
2002                            && { ra.add(2).value_unchecked().is_number() }
2003                            && { ra.add(2).value_unchecked().number_value() == 0.0 }
2004                        {
2005                            {
2006                                ra_value.set_nil();
2007                                ra.add(2)
2008                                    .value_unchecked()
2009                                    .set_light_userdata(ptr::null_mut(), USERDATA_TAG_LIMIT as i32);
2010                            }
2011                        } else if !ra_value.is_function() {
2012                            thread.set_vm_saved_pc(pc);
2013                            return thread
2014                                .type_error(ra_value, "iterate over")
2015                                .map_err(Into::into);
2016                        }
2017
2018                        pc = insn_pc.add(1).offset(i32::from(instruction.d()) as isize);
2019                        proto.assert_vm_pc(pc);
2020                    }
2021                    Opcode::ForGPrepNext => {
2022                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
2023                        let ra_value = ra.value_unchecked();
2024                        let env = closure.env();
2025
2026                        if { env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0 }
2027                            && { ra.add(1).value_unchecked().is_table() }
2028                            && { ra.add(2).value_unchecked().is_nil() }
2029                        {
2030                            {
2031                                ra_value.set_nil();
2032                                ra.add(2)
2033                                    .value_unchecked()
2034                                    .set_light_userdata(ptr::null_mut(), USERDATA_TAG_LIMIT as i32);
2035                            }
2036                        } else if !ra_value.is_function() {
2037                            thread.set_vm_saved_pc(pc);
2038                            return thread
2039                                .type_error(ra_value, "iterate over")
2040                                .map_err(Into::into);
2041                        }
2042
2043                        pc = insn_pc.add(1).offset(i32::from(instruction.d()) as isize);
2044                        proto.assert_vm_pc(pc);
2045                    }
2046                    Opcode::GetVarargs => {
2047                        let b = i32::from(instruction.b()) - 1;
2048                        let n = { base.offset_from(thread.current_call_info().function()) } as i32
2049                            - i32::from(proto.as_ptr().as_ref().unwrap_unchecked().num_params)
2050                            - 1;
2051
2052                        if b == LUA_MULTRET {
2053                            thread.set_vm_saved_pc(pc);
2054                            thread.check_stack_internal(n)?;
2055                            base = thread.stack_base();
2056
2057                            let ra =
2058                                base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
2059                            let varargs = { base.sub(n as usize) };
2060
2061                            for index in 0..n {
2062                                ra.add(index as usize)
2063                                    .value_unchecked()
2064                                    .set_obj(varargs.add(index as usize).value_unchecked());
2065                            }
2066
2067                            thread.set_stack_top(ra.add(n as usize));
2068                        } else {
2069                            let ra =
2070                                base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
2071                            let varargs = { base.sub(n.max(0) as usize) };
2072
2073                            for index in 0..b.min(n) {
2074                                ra.add(index as usize)
2075                                    .value_unchecked()
2076                                    .set_obj(varargs.add(index as usize).value_unchecked());
2077                            }
2078                            for index in n.max(0)..b {
2079                                ra.add(index as usize).value_unchecked().set_nil();
2080                            }
2081                        }
2082                    }
2083                    Opcode::PrepVarargs => {
2084                        let num_params = instruction.a() as usize;
2085                        thread.set_vm_saved_pc(pc);
2086                        thread.check_stack_internal(
2087                            i32::from(closure.as_ptr().as_ref().unwrap_unchecked().stack_size)
2088                                + num_params as i32,
2089                        )?;
2090
2091                        base = thread.stack_base();
2092                        debug_assert!(thread.stack_top().offset_from(base) as usize >= num_params);
2093
2094                        let fixed = base;
2095                        base = thread.stack_top();
2096
2097                        for index in 0..num_params {
2098                            base.add(index)
2099                                .value_unchecked()
2100                                .set_obj(fixed.add(index).value_unchecked());
2101                            fixed.add(index).value_unchecked().set_nil();
2102                        }
2103
2104                        let current_call_info = thread.current_call_info();
2105                        let new_top = base
2106                            .add(closure.as_ptr().as_ref().unwrap_unchecked().stack_size as usize);
2107                        current_call_info.set_base(base);
2108                        current_call_info.set_top(new_top);
2109                        thread.set_stack_base(base);
2110                        thread.set_stack_top(new_top);
2111                    }
2112                    Opcode::NativeCall => {
2113                        debug_assert!(!{
2114                            proto
2115                                .as_ptr()
2116                                .as_ref()
2117                                .unwrap_unchecked()
2118                                .exec_data
2119                                .is_null()
2120                        });
2121
2122                        {
2123                            let current_call_info = thread.current_call_info();
2124                            current_call_info.as_ptr().as_mut().unwrap_unchecked().flags =
2125                                LUA_CALLINFO_NATIVE;
2126                            current_call_info.set_saved_pc(
2127                                proto.as_ptr().as_ref().unwrap_unchecked().code.cast_const(),
2128                            );
2129                        }
2130
2131                        let Some(enter) = global.execution_enter() else {
2132                            unreachable!("native lvmexecute requires an execution enter callback");
2133                        };
2134
2135                        if { enter(thread, proto) } == 0 {
2136                            return Ok(());
2137                        }
2138
2139                        let call_info = thread.current_call_info();
2140                        closure = call_info.function_closure();
2141                        proto = closure.proto().unwrap_unchecked();
2142                        pc = call_info.saved_pc();
2143                        base = thread.stack_base();
2144                        constants = proto.constants();
2145                        proto.assert_vm_pc(pc);
2146                    }
2147                    Opcode::Jump => {
2148                        pc = pc.offset(i32::from(instruction.d()) as isize);
2149                        proto.assert_vm_pc(pc);
2150                    }
2151                    Opcode::JumpBack => {
2152                        thread.interrupt_vm(insn_pc)?;
2153                        base = thread.stack_base();
2154                        if flags::LuauBackedgeHeapCheck.get() && thread.needs_gc() {
2155                            thread.set_vm_saved_pc(pc);
2156                            thread.step(true)?;
2157                            base = thread.stack_base();
2158                        }
2159
2160                        pc = pc.offset(i32::from(instruction.d()) as isize);
2161                        proto.assert_vm_pc(pc);
2162                    }
2163                    Opcode::JumpIf => {
2164                        let ra = base
2165                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2166                            .value_unchecked();
2167                        if !{ ra.is_false() } {
2168                            pc = pc.offset(i32::from(instruction.d()) as isize);
2169                        }
2170                        proto.assert_vm_pc(pc);
2171                    }
2172                    Opcode::JumpIfNot => {
2173                        let ra = base
2174                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2175                            .value_unchecked();
2176                        if ra.is_false() {
2177                            pc = pc.offset(i32::from(instruction.d()) as isize);
2178                        }
2179                        proto.assert_vm_pc(pc);
2180                    }
2181                    Opcode::JumpIfEq => {
2182                        let aux = { (*pc).word() };
2183                        let ra = base
2184                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2185                            .value_unchecked();
2186                        let rb = base
2187                            .vm_reg_cursor(thread.stack_top(), aux as usize)
2188                            .value_unchecked();
2189
2190                        if ra.tt() == rb.tt() {
2191                            match ra.tt() {
2192                                x if x == LUA_TNIL => {
2193                                    pc = pc.offset(i32::from(instruction.d()) as isize);
2194                                }
2195                                x if x == LUA_TBOOLEAN => {
2196                                    pc = if ra.boolean_value() == rb.boolean_value() {
2197                                        pc.offset(i32::from(instruction.d()) as isize)
2198                                    } else {
2199                                        pc.add(1)
2200                                    };
2201                                }
2202                                x if x == LUA_TLIGHTUSERDATA => {
2203                                    pc = if ra.pointer_value() == rb.pointer_value()
2204                                        && ra.light_userdata_tag() == rb.light_userdata_tag()
2205                                    {
2206                                        pc.offset(i32::from(instruction.d()) as isize)
2207                                    } else {
2208                                        pc.add(1)
2209                                    };
2210                                }
2211                                x if x == LUA_TNUMBER => {
2212                                    pc = if ra.number_value() == rb.number_value() {
2213                                        pc.offset(i32::from(instruction.d()) as isize)
2214                                    } else {
2215                                        pc.add(1)
2216                                    };
2217                                }
2218                                x if x == LUA_TVECTOR => {
2219                                    pc = if ra.vector_eq(rb) {
2220                                        pc.offset(i32::from(instruction.d()) as isize)
2221                                    } else {
2222                                        pc.add(1)
2223                                    };
2224                                }
2225                                LUA_TSTRING | LUA_TFUNCTION | LUA_TTHREAD | LUA_TBUFFER => {
2226                                    pc = if ra.gc_value() == rb.gc_value() {
2227                                        pc.offset(i32::from(instruction.d()) as isize)
2228                                    } else {
2229                                        pc.add(1)
2230                                    };
2231                                }
2232                                x if x == LUA_TTABLE => {
2233                                    let left = { ra.table_value() };
2234                                    let right = { rb.table_value() };
2235
2236                                    if left.metatable() == right.metatable() {
2237                                        let function =
2238                                            thread.fast_tm(left.metatable(), TmEvent::Eq);
2239
2240                                        if function.is_none() {
2241                                            pc = if left == right {
2242                                                pc.offset(i32::from(instruction.d()) as isize)
2243                                            } else {
2244                                                pc.add(1)
2245                                            };
2246                                            proto.assert_vm_pc(pc);
2247                                            break 'dispatch;
2248                                        }
2249                                    }
2250
2251                                    thread.set_vm_saved_pc(pc);
2252                                    let result = thread.equal_value(ra, rb)?;
2253
2254                                    pc = if result == 1 {
2255                                        pc.offset(i32::from(instruction.d()) as isize)
2256                                    } else {
2257                                        pc.add(1)
2258                                    };
2259                                    base = thread.stack_base();
2260                                }
2261                                x if x == LUA_TUSERDATA => {
2262                                    let left = { ra.userdata_value() };
2263                                    let right = { rb.userdata_value() };
2264
2265                                    if left.metatable() == right.metatable() {
2266                                        let function =
2267                                            thread.fast_tm(left.metatable(), TmEvent::Eq);
2268
2269                                        if function.is_none() {
2270                                            pc = if left == right {
2271                                                pc.offset(i32::from(instruction.d()) as isize)
2272                                            } else {
2273                                                pc.add(1)
2274                                            };
2275                                            proto.assert_vm_pc(pc);
2276                                            break 'dispatch;
2277                                        } else if let Some(function) = function
2278                                            && {
2279                                                function.is_function()
2280                                                    && function.is_native_function()
2281                                            }
2282                                        {
2283                                            let top_cursor = thread.stack_top();
2284                                            debug_assert!({
2285                                                top_cursor.add(3)
2286                                                    < thread.stack().add(
2287                                                        thread
2288                                                            .as_ptr()
2289                                                            .as_ref()
2290                                                            .unwrap_unchecked()
2291                                                            .stack_size
2292                                                            as usize,
2293                                                    )
2294                                            });
2295
2296                                            let result = { top_cursor.offset_from(base) as i32 };
2297                                            {
2298                                                top_cursor.value_unchecked().set_obj(function);
2299                                                top_cursor.add(1).value_unchecked().set_obj(ra);
2300                                                top_cursor.add(2).value_unchecked().set_obj(rb);
2301                                                thread.set_stack_top(top_cursor.add(3));
2302                                            }
2303
2304                                            thread.set_vm_saved_pc(pc);
2305                                            thread.call_tm(2, result)?;
2306                                            base = thread.stack_base();
2307
2308                                            let result_slot = { base.add(result as usize) };
2309                                            pc = if !result_slot.value_unchecked().is_false() {
2310                                                pc.offset(i32::from(instruction.d()) as isize)
2311                                            } else {
2312                                                pc.add(1)
2313                                            };
2314                                            proto.assert_vm_pc(pc);
2315                                            break 'dispatch;
2316                                        }
2317                                    }
2318
2319                                    thread.set_vm_saved_pc(pc);
2320                                    let result = thread.equal_value(ra, rb)?;
2321
2322                                    pc = if result == 1 {
2323                                        pc.offset(i32::from(instruction.d()) as isize)
2324                                    } else {
2325                                        pc.add(1)
2326                                    };
2327                                    base = thread.stack_base();
2328                                }
2329                                x if x == LUA_TCLASS => {
2330                                    pc = if ra.class_value() == rb.class_value() {
2331                                        pc.offset(i32::from(instruction.d()) as isize)
2332                                    } else {
2333                                        pc.add(1)
2334                                    };
2335                                }
2336                                x if x == LUA_TOBJECT => {
2337                                    thread.set_vm_saved_pc(pc);
2338                                    let result = thread.equal_value(ra, rb)?;
2339
2340                                    pc = if result == 1 {
2341                                        pc.offset(i32::from(instruction.d()) as isize)
2342                                    } else {
2343                                        pc.add(1)
2344                                    };
2345                                    base = thread.stack_base();
2346                                }
2347                                x if x == LUA_TINTEGER => {
2348                                    pc = if ra.integer_value() == rb.integer_value() {
2349                                        pc.offset(i32::from(instruction.d()) as isize)
2350                                    } else {
2351                                        pc.add(1)
2352                                    };
2353                                }
2354                                _ => unreachable!("unknown jump equality type"),
2355                            }
2356                        } else {
2357                            pc = pc.add(1);
2358                        }
2359
2360                        proto.assert_vm_pc(pc);
2361                    }
2362                    Opcode::JumpIfNotEq => {
2363                        let aux = { (*pc).word() };
2364                        let ra = base
2365                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2366                            .value_unchecked();
2367                        let rb = base
2368                            .vm_reg_cursor(thread.stack_top(), aux as usize)
2369                            .value_unchecked();
2370
2371                        if ra.tt() == rb.tt() {
2372                            match ra.tt() {
2373                                x if x == LUA_TNIL => {
2374                                    pc = pc.add(1);
2375                                }
2376                                x if x == LUA_TBOOLEAN => {
2377                                    pc = if ra.boolean_value() != rb.boolean_value() {
2378                                        pc.offset(i32::from(instruction.d()) as isize)
2379                                    } else {
2380                                        pc.add(1)
2381                                    };
2382                                }
2383                                x if x == LUA_TLIGHTUSERDATA => {
2384                                    pc = if ra.pointer_value() != rb.pointer_value()
2385                                        || ra.light_userdata_tag() != rb.light_userdata_tag()
2386                                    {
2387                                        pc.offset(i32::from(instruction.d()) as isize)
2388                                    } else {
2389                                        pc.add(1)
2390                                    };
2391                                }
2392                                x if x == LUA_TNUMBER => {
2393                                    pc = if ra.number_value() != rb.number_value() {
2394                                        pc.offset(i32::from(instruction.d()) as isize)
2395                                    } else {
2396                                        pc.add(1)
2397                                    };
2398                                }
2399                                x if x == LUA_TVECTOR => {
2400                                    pc = if !ra.vector_eq(rb) {
2401                                        pc.offset(i32::from(instruction.d()) as isize)
2402                                    } else {
2403                                        pc.add(1)
2404                                    };
2405                                }
2406                                LUA_TSTRING | LUA_TFUNCTION | LUA_TTHREAD | LUA_TBUFFER => {
2407                                    pc = if ra.gc_value() != rb.gc_value() {
2408                                        pc.offset(i32::from(instruction.d()) as isize)
2409                                    } else {
2410                                        pc.add(1)
2411                                    };
2412                                }
2413                                x if x == LUA_TTABLE => {
2414                                    let left = { ra.table_value() };
2415                                    let right = { rb.table_value() };
2416
2417                                    if left.metatable() == right.metatable() {
2418                                        let function =
2419                                            thread.fast_tm(left.metatable(), TmEvent::Eq);
2420
2421                                        if function.is_none() {
2422                                            pc = if left != right {
2423                                                pc.offset(i32::from(instruction.d()) as isize)
2424                                            } else {
2425                                                pc.add(1)
2426                                            };
2427                                            proto.assert_vm_pc(pc);
2428                                            break 'dispatch;
2429                                        }
2430                                    }
2431
2432                                    thread.set_vm_saved_pc(pc);
2433                                    let result = thread.equal_value(ra, rb)?;
2434
2435                                    pc = if result == 0 {
2436                                        pc.offset(i32::from(instruction.d()) as isize)
2437                                    } else {
2438                                        pc.add(1)
2439                                    };
2440                                    base = thread.stack_base();
2441                                }
2442                                x if x == LUA_TUSERDATA => {
2443                                    let left = { ra.userdata_value() };
2444                                    let right = { rb.userdata_value() };
2445
2446                                    if left.metatable() == right.metatable() {
2447                                        let function =
2448                                            thread.fast_tm(left.metatable(), TmEvent::Eq);
2449
2450                                        if function.is_none() {
2451                                            pc = if left != right {
2452                                                pc.offset(i32::from(instruction.d()) as isize)
2453                                            } else {
2454                                                pc.add(1)
2455                                            };
2456                                            proto.assert_vm_pc(pc);
2457                                            break 'dispatch;
2458                                        } else if let Some(function) = function
2459                                            && {
2460                                                function.is_function()
2461                                                    && function.is_native_function()
2462                                            }
2463                                        {
2464                                            let top_cursor = thread.stack_top();
2465                                            debug_assert!({
2466                                                top_cursor.add(3)
2467                                                    < thread.stack().add(
2468                                                        thread
2469                                                            .as_ptr()
2470                                                            .as_ref()
2471                                                            .unwrap_unchecked()
2472                                                            .stack_size
2473                                                            as usize,
2474                                                    )
2475                                            });
2476
2477                                            let result = { top_cursor.offset_from(base) as i32 };
2478                                            {
2479                                                top_cursor.value_unchecked().set_obj(function);
2480                                                top_cursor.add(1).value_unchecked().set_obj(ra);
2481                                                top_cursor.add(2).value_unchecked().set_obj(rb);
2482                                                thread.set_stack_top(top_cursor.add(3));
2483                                            }
2484
2485                                            thread.set_vm_saved_pc(pc);
2486                                            thread.call_tm(2, result)?;
2487                                            base = thread.stack_base();
2488
2489                                            let result_slot = { base.add(result as usize) };
2490                                            pc = if result_slot.value_unchecked().is_false() {
2491                                                pc.offset(i32::from(instruction.d()) as isize)
2492                                            } else {
2493                                                pc.add(1)
2494                                            };
2495                                            proto.assert_vm_pc(pc);
2496                                            break 'dispatch;
2497                                        }
2498                                    }
2499
2500                                    thread.set_vm_saved_pc(pc);
2501                                    let result = thread.equal_value(ra, rb)?;
2502
2503                                    pc = if result == 0 {
2504                                        pc.offset(i32::from(instruction.d()) as isize)
2505                                    } else {
2506                                        pc.add(1)
2507                                    };
2508                                    base = thread.stack_base();
2509                                }
2510                                x if x == LUA_TCLASS => {
2511                                    pc = if ra.class_value() != rb.class_value() {
2512                                        pc.offset(i32::from(instruction.d()) as isize)
2513                                    } else {
2514                                        pc.add(1)
2515                                    };
2516                                }
2517                                x if x == LUA_TOBJECT => {
2518                                    thread.set_vm_saved_pc(pc);
2519                                    let result = thread.equal_value(ra, rb)?;
2520
2521                                    pc = if result == 0 {
2522                                        pc.offset(i32::from(instruction.d()) as isize)
2523                                    } else {
2524                                        pc.add(1)
2525                                    };
2526                                    base = thread.stack_base();
2527                                }
2528                                x if x == LUA_TINTEGER => {
2529                                    pc = if ra.integer_value() != rb.integer_value() {
2530                                        pc.offset(i32::from(instruction.d()) as isize)
2531                                    } else {
2532                                        pc.add(1)
2533                                    };
2534                                }
2535                                _ => unreachable!("unknown jump equality type"),
2536                            }
2537                        } else {
2538                            pc = pc.offset(i32::from(instruction.d()) as isize);
2539                        }
2540
2541                        proto.assert_vm_pc(pc);
2542                    }
2543                    Opcode::JumpIfLe => {
2544                        let aux = { (*pc).word() };
2545                        let ra = base
2546                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2547                            .value_unchecked();
2548                        let rb = base
2549                            .vm_reg_cursor(thread.stack_top(), aux as usize)
2550                            .value_unchecked();
2551
2552                        if ra.is_number() && rb.is_number() {
2553                            pc = if ra.number_value() <= rb.number_value() {
2554                                pc.offset(i32::from(instruction.d()) as isize)
2555                            } else {
2556                                pc.add(1)
2557                            };
2558                        } else if ra.is_string() && rb.is_string() {
2559                            pc = if string_compare(ra.string_value(), rb.string_value()) <= 0 {
2560                                pc.offset(i32::from(instruction.d()) as isize)
2561                            } else {
2562                                pc.add(1)
2563                            };
2564                        } else {
2565                            thread.set_vm_saved_pc(pc);
2566                            let result = thread.less_equal(ra, rb)?;
2567                            pc = if result == 1 {
2568                                pc.offset(i32::from(instruction.d()) as isize)
2569                            } else {
2570                                pc.add(1)
2571                            };
2572                            base = thread.stack_base();
2573                        }
2574
2575                        proto.assert_vm_pc(pc);
2576                    }
2577                    Opcode::JumpIfNotLe => {
2578                        let aux = { (*pc).word() };
2579                        let ra = base
2580                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2581                            .value_unchecked();
2582                        let rb = base
2583                            .vm_reg_cursor(thread.stack_top(), aux as usize)
2584                            .value_unchecked();
2585
2586                        if ra.is_number() && rb.is_number() {
2587                            pc = if ra.number_value() <= rb.number_value() {
2588                                pc.add(1)
2589                            } else {
2590                                pc.offset(i32::from(instruction.d()) as isize)
2591                            };
2592                        } else if ra.is_string() && rb.is_string() {
2593                            pc = if string_compare(ra.string_value(), rb.string_value()) > 0 {
2594                                pc.offset(i32::from(instruction.d()) as isize)
2595                            } else {
2596                                pc.add(1)
2597                            };
2598                        } else {
2599                            thread.set_vm_saved_pc(pc);
2600                            let result = thread.less_equal(ra, rb)?;
2601                            pc = if result == 0 {
2602                                pc.offset(i32::from(instruction.d()) as isize)
2603                            } else {
2604                                pc.add(1)
2605                            };
2606                            base = thread.stack_base();
2607                        }
2608
2609                        proto.assert_vm_pc(pc);
2610                    }
2611                    Opcode::JumpIfLt => {
2612                        let aux = { (*pc).word() };
2613                        let ra = base
2614                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2615                            .value_unchecked();
2616                        let rb = base
2617                            .vm_reg_cursor(thread.stack_top(), aux as usize)
2618                            .value_unchecked();
2619
2620                        if ra.is_number() && rb.is_number() {
2621                            pc = if ra.number_value() < rb.number_value() {
2622                                pc.offset(i32::from(instruction.d()) as isize)
2623                            } else {
2624                                pc.add(1)
2625                            };
2626                        } else if ra.is_string() && rb.is_string() {
2627                            pc = if string_compare(ra.string_value(), rb.string_value()) < 0 {
2628                                pc.offset(i32::from(instruction.d()) as isize)
2629                            } else {
2630                                pc.add(1)
2631                            };
2632                        } else {
2633                            thread.set_vm_saved_pc(pc);
2634                            let result = thread.less_than_internal(ra, rb)?;
2635                            pc = if result == 1 {
2636                                pc.offset(i32::from(instruction.d()) as isize)
2637                            } else {
2638                                pc.add(1)
2639                            };
2640                            base = thread.stack_base();
2641                        }
2642
2643                        proto.assert_vm_pc(pc);
2644                    }
2645                    Opcode::JumpIfNotLt => {
2646                        let aux = { *pc };
2647                        let ra = base
2648                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2649                            .value_unchecked();
2650                        let rb = base
2651                            .vm_reg_cursor(thread.stack_top(), aux as usize)
2652                            .value_unchecked();
2653
2654                        if ra.is_number() && rb.is_number() {
2655                            pc = if ra.number_value() < rb.number_value() {
2656                                pc.add(1)
2657                            } else {
2658                                pc.offset(i32::from(instruction.d()) as isize)
2659                            };
2660                        } else if ra.is_string() && rb.is_string() {
2661                            pc = if string_compare(ra.string_value(), rb.string_value()) >= 0 {
2662                                pc.offset(i32::from(instruction.d()) as isize)
2663                            } else {
2664                                pc.add(1)
2665                            };
2666                        } else {
2667                            thread.set_vm_saved_pc(pc);
2668                            let result = thread.less_than_internal(ra, rb)?;
2669                            pc = if result == 0 {
2670                                pc.offset(i32::from(instruction.d()) as isize)
2671                            } else {
2672                                pc.add(1)
2673                            };
2674                            base = thread.stack_base();
2675                        }
2676
2677                        proto.assert_vm_pc(pc);
2678                    }
2679                    Opcode::LoadKx => {
2680                        let ra = base
2681                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2682                            .value_unchecked();
2683                        let aux = { InstructionAux::new((*pc).word()) };
2684                        pc = pc.add(1);
2685                        let kv = proto.vm_const(constants, aux.word() as usize);
2686                        {
2687                            ra.set_obj(kv);
2688                        }
2689                    }
2690                    Opcode::GetImport => {
2691                        let ra_cursor =
2692                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
2693                        let ra = ra_cursor.value_unchecked();
2694                        let kv = proto.vm_const(constants, instruction.d() as u16 as usize);
2695                        let env = closure.env();
2696
2697                        if { !kv.is_nil() } && {
2698                            env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0
2699                        } {
2700                            {
2701                                ra.set_obj(kv);
2702                            }
2703                            pc = pc.add(1);
2704                            proto.assert_vm_pc(pc);
2705                        } else {
2706                            let aux = { InstructionAux::new((*pc).word()) };
2707                            pc = pc.add(1);
2708
2709                            thread.set_vm_saved_pc(pc);
2710                            thread.get_import(env, constants, ra_cursor, aux.word(), false)?;
2711                            base = thread.stack_base();
2712                        }
2713                    }
2714                    Opcode::GetTableKs => {
2715                        let ra_cursor =
2716                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
2717                        let ra = ra_cursor.value_unchecked();
2718                        let rb = base
2719                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
2720                            .value_unchecked();
2721                        let aux = { InstructionAux::new((*pc).word()) };
2722                        pc = pc.add(1);
2723                        let kv = proto.vm_const(constants, aux.word() as usize);
2724                        debug_assert!({ kv.is_string() });
2725                        let kv_string = { kv.string_value() };
2726
2727                        if rb.is_table() {
2728                            let table = { rb.table_value() };
2729                            let slot = instruction.c() as usize & table.node_mask_8();
2730                            let node = { table.node(slot as i32) };
2731
2732                            if node.has_string_key(kv_string) && !node.value_is_nil() {
2733                                ra.set_obj(node.value_unchecked());
2734                            } else if table.metatable().is_none() {
2735                                if let Some(node_cursor) = table.get_str_node(kv_string) {
2736                                    let cached_slot = { table.node_index(node_cursor) };
2737                                    patch_instruction_c(
2738                                        insn_pc as *mut Instruction,
2739                                        cached_slot as u8,
2740                                    );
2741                                    ra.set_obj(node_cursor.node_unchecked().value_unchecked());
2742                                } else {
2743                                    ra.set_nil();
2744                                }
2745                            } else {
2746                                thread.set_cached_slot(slot as i32);
2747                                thread.set_vm_saved_pc(pc);
2748                                thread.get_table_internal(rb, kv, ra_cursor)?;
2749                                let cached_slot = thread.cached_slot();
2750                                patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
2751                                base = thread.stack_base();
2752                            }
2753                        } else {
2754                            let direct_field = flags::LuauDirectFieldGet.get();
2755                            if direct_field && { rb.is_userdata() } {
2756                                let userdata = { rb.userdata_value() };
2757                                if let Some(dispatch) = global.userdata_direct_field(
2758                                    userdata.as_ptr().as_ref().unwrap_unchecked().tag as usize,
2759                                ) {
2760                                    let slot = instruction.c() as usize & dispatch.node_mask_8();
2761                                    let node = { dispatch.node(slot as i32) };
2762
2763                                    if node.has_string_key(kv_string) && !node.value_is_nil() {
2764                                        let function: LuaUserdataDirectFieldGet =
2765                                            std::mem::transmute(
2766                                                node.value_unchecked().pointer_value(),
2767                                            );
2768                                        let mut result = UserdataDirectFieldResult(ra);
2769                                        {
2770                                            function(userdata.data_mut_ptr().cast(), &mut result);
2771                                        }
2772                                        break 'dispatch;
2773                                    }
2774
2775                                    if let Some(node_cursor) = dispatch.get_str_node(kv_string) {
2776                                        let cached_slot = dispatch.node_index(node_cursor);
2777                                        patch_instruction_c(
2778                                            insn_pc as *mut Instruction,
2779                                            cached_slot as u8,
2780                                        );
2781
2782                                        let function: LuaUserdataDirectFieldGet =
2783                                            std::mem::transmute(
2784                                                node_cursor
2785                                                    .node_unchecked()
2786                                                    .value_unchecked()
2787                                                    .pointer_value(),
2788                                            );
2789                                        let mut result = UserdataDirectFieldResult(ra);
2790                                        {
2791                                            function(userdata.data_mut_ptr().cast(), &mut result);
2792                                        }
2793                                        break 'dispatch;
2794                                    }
2795                                }
2796                            }
2797
2798                            if rb.is_userdata() {
2799                                let userdata = { rb.userdata_value() };
2800                                if let Some(function) =
2801                                    thread.fast_tm(userdata.metatable(), TmEvent::Index)
2802                                    && { function.is_function() && function.is_native_function() }
2803                                {
2804                                    let top_cursor = thread.stack_top();
2805                                    debug_assert!({
2806                                        top_cursor.add(3)
2807                                            < thread.stack().add(
2808                                                thread
2809                                                    .as_ptr()
2810                                                    .as_ref()
2811                                                    .unwrap_unchecked()
2812                                                    .stack_size
2813                                                    as usize,
2814                                            )
2815                                    });
2816                                    {
2817                                        top_cursor.value_unchecked().set_obj(function);
2818                                        top_cursor.add(1).value_unchecked().set_obj(rb);
2819                                        top_cursor.add(2).value_unchecked().set_obj(kv);
2820                                        thread.set_stack_top(top_cursor.add(3));
2821                                        thread.set_cached_slot(i32::from(instruction.c()));
2822                                    }
2823
2824                                    thread.set_vm_saved_pc(pc);
2825                                    thread.call_tm(2, i32::from(instruction.a()))?;
2826                                    let cached_slot = thread.cached_slot();
2827                                    patch_instruction_c(
2828                                        insn_pc as *mut Instruction,
2829                                        cached_slot as u8,
2830                                    );
2831                                    base = thread.stack_base();
2832                                    break 'dispatch;
2833                                }
2834                            } else if rb.is_vector() {
2835                                let name = { kv_string.as_bytes() };
2836                                if name.len() == 1 {
2837                                    let component = match name[0] | b' ' {
2838                                        b'x' => Some(0usize),
2839                                        b'y' => Some(1usize),
2840                                        b'z' => Some(2usize),
2841                                        #[cfg(feature = "vector4")]
2842                                        b'w' => Some(3usize),
2843                                        _ => None,
2844                                    };
2845
2846                                    if let Some(component) = component
2847                                        && component < LUA_VECTOR_SIZE
2848                                    {
2849                                        let vector = { rb.vector_ptr() };
2850                                        {
2851                                            ra.set_number(match component {
2852                                                0 => *vector,
2853                                                1 => *vector.add(1),
2854                                                2 => *vector.add(2),
2855                                                #[cfg(feature = "vector4")]
2856                                                3 => vector_w_ptr(vector),
2857                                                _ => unreachable!(),
2858                                            }
2859                                                as f64);
2860                                        }
2861                                        break 'dispatch;
2862                                    }
2863                                }
2864
2865                                let vector_metatable = global.metatable(LUA_TVECTOR as usize);
2866                                if let Some(function) =
2867                                    thread.fast_tm(vector_metatable, TmEvent::Index)
2868                                    && { function.is_function() && function.is_native_function() }
2869                                {
2870                                    let top_cursor = thread.stack_top();
2871                                    debug_assert!({
2872                                        top_cursor.add(3)
2873                                            < thread.stack().add(
2874                                                thread
2875                                                    .as_ptr()
2876                                                    .as_ref()
2877                                                    .unwrap_unchecked()
2878                                                    .stack_size
2879                                                    as usize,
2880                                            )
2881                                    });
2882                                    {
2883                                        top_cursor.value_unchecked().set_obj(function);
2884                                        top_cursor.add(1).value_unchecked().set_obj(rb);
2885                                        top_cursor.add(2).value_unchecked().set_obj(kv);
2886                                        thread.set_stack_top(top_cursor.add(3));
2887                                        thread.set_cached_slot(i32::from(instruction.c()));
2888                                    }
2889
2890                                    thread.set_vm_saved_pc(pc);
2891                                    thread.call_tm(2, i32::from(instruction.a()))?;
2892                                    let cached_slot = thread.cached_slot();
2893                                    patch_instruction_c(
2894                                        insn_pc as *mut Instruction,
2895                                        cached_slot as u8,
2896                                    );
2897                                    base = thread.stack_base();
2898                                    break 'dispatch;
2899                                }
2900                            } else if flags::DebugLuauUserDefinedClassesRuntime.get() && {
2901                                rb.is_object()
2902                            } {
2903                                let instance = { rb.object_value() };
2904                                match instance.lookup_member_cached(kv_string, instruction.c()) {
2905                                    ObjectMemberLookup::Cached(member) => {
2906                                        ra.set_obj(member);
2907                                    }
2908                                    ObjectMemberLookup::Resolved { offset, member } => {
2909                                        ra.set_obj(member);
2910                                        patch_instruction_c(
2911                                            insn_pc as *mut Instruction,
2912                                            offset as u8,
2913                                        );
2914                                    }
2915                                    ObjectMemberLookup::Missing => {
2916                                        return thread
2917                                            .missing_member_error(rb, kv)
2918                                            .map_err(Into::into);
2919                                    }
2920                                }
2921                                break 'dispatch;
2922                            } else {
2923                                thread.set_vm_saved_pc(pc);
2924                                thread.get_table_internal(rb, kv, ra_cursor)?;
2925                                base = thread.stack_base();
2926                            }
2927                        }
2928                    }
2929                    Opcode::SetTableKs => {
2930                        let ra = base
2931                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
2932                            .value_unchecked();
2933                        let rb = base
2934                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
2935                            .value_unchecked();
2936                        let aux = { InstructionAux::new((*pc).word()) };
2937                        pc = pc.add(1);
2938                        let kv = proto.vm_const(constants, aux.word() as usize);
2939                        debug_assert!({ kv.is_string() });
2940                        let kv_string = { kv.string_value() };
2941
2942                        if rb.is_table() {
2943                            let table = { rb.table_value() };
2944                            let slot = instruction.c() as usize & table.node_mask_8();
2945                            let node = { table.node(slot as i32) };
2946
2947                            if node.has_string_key(kv_string)
2948                                && !node.value_is_nil()
2949                                && table.as_ptr().as_ref().unwrap_unchecked().readonly == 0
2950                            {
2951                                node.value_unchecked().set_obj(ra);
2952                                if ra.is_collectable() {
2953                                    let table_object: GcObject = table.into();
2954                                    let child = ra.gc_value();
2955                                    if table_object.is_black() && child.is_white() {
2956                                        thread.barrier_table(table, child);
2957                                    }
2958                                }
2959                            } else if thread.fast_notm(table.metatable(), TmEvent::NewIndex)
2960                                && table.as_ptr().as_ref().unwrap_unchecked().readonly == 0
2961                            {
2962                                thread.set_vm_saved_pc(pc);
2963                                let node_cursor = thread.set_str(table, kv_string)?;
2964                                let cached_slot = { table.node_index(node_cursor) };
2965                                patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
2966                                node_cursor.node_unchecked().value_unchecked().set_obj(ra);
2967                                if ra.is_collectable() {
2968                                    let table_object: GcObject = table.into();
2969                                    let child = ra.gc_value();
2970                                    if table_object.is_black() && child.is_white() {
2971                                        thread.barrier_table(table, child);
2972                                    }
2973                                }
2974                                base = thread.stack_base();
2975                            } else {
2976                                thread.set_cached_slot(slot as i32);
2977                                thread.set_vm_saved_pc(pc);
2978                                thread.set_table_internal(rb, kv, ra)?;
2979                                let cached_slot = thread.cached_slot();
2980                                patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
2981                                base = thread.stack_base();
2982                            }
2983                        } else if rb.is_userdata() {
2984                            let userdata = { rb.userdata_value() };
2985                            if let Some(function) =
2986                                thread.fast_tm(userdata.metatable(), TmEvent::NewIndex)
2987                                && { function.is_function() && function.is_native_function() }
2988                            {
2989                                let top_cursor = thread.stack_top();
2990                                debug_assert!({
2991                                    top_cursor.add(4)
2992                                        < thread.stack().add(
2993                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
2994                                                as usize,
2995                                        )
2996                                });
2997                                {
2998                                    top_cursor.value_unchecked().set_obj(function);
2999                                    top_cursor.add(1).value_unchecked().set_obj(rb);
3000                                    top_cursor.add(2).value_unchecked().set_obj(kv);
3001                                    top_cursor.add(3).value_unchecked().set_obj(ra);
3002                                    thread.set_stack_top(top_cursor.add(4));
3003                                    thread.set_cached_slot(i32::from(instruction.c()));
3004                                }
3005
3006                                thread.set_vm_saved_pc(pc);
3007                                thread.call_tm(3, -1)?;
3008                                let cached_slot = thread.cached_slot();
3009                                patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
3010                                base = thread.stack_base();
3011                            } else {
3012                                thread.set_vm_saved_pc(pc);
3013                                thread.set_table_internal(rb, kv, ra)?;
3014                                base = thread.stack_base();
3015                            }
3016                        } else {
3017                            thread.set_vm_saved_pc(pc);
3018                            thread.set_table_internal(rb, kv, ra)?;
3019                            base = thread.stack_base();
3020                        }
3021                    }
3022                    Opcode::GetTable => {
3023                        let ra_cursor =
3024                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
3025                        let ra = ra_cursor.value_unchecked();
3026                        let rb = base
3027                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3028                            .value_unchecked();
3029                        let rc = base
3030                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
3031                            .value_unchecked();
3032
3033                        if rb.is_table() && rc.is_number() {
3034                            let table = rb.table_value();
3035                            let indexd = rc.number_value();
3036                            let index = indexd as i32;
3037
3038                            if (index as u32).wrapping_sub(1)
3039                                < table.as_ptr().as_ref().unwrap_unchecked().size_array as u32
3040                                && table
3041                                    .as_ptr()
3042                                    .as_ref()
3043                                    .unwrap_unchecked()
3044                                    .metatable
3045                                    .is_null()
3046                                && (index as f64) == indexd
3047                            {
3048                                ra.set_obj(table.array_slot((index - 1) as usize));
3049                                break 'dispatch;
3050                            }
3051                        }
3052
3053                        thread.set_vm_saved_pc(pc);
3054                        thread.get_table_internal(rb, rc, ra_cursor)?;
3055                        base = thread.stack_base();
3056                    }
3057                    Opcode::SetTable => {
3058                        let ra = base
3059                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
3060                            .value_unchecked();
3061                        let rb = base
3062                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3063                            .value_unchecked();
3064                        let rc = base
3065                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
3066                            .value_unchecked();
3067                        if rb.is_table() && rc.is_number() {
3068                            let table = { rb.table_value() };
3069                            let indexd = { rc.number_value() };
3070                            let index = indexd as i32;
3071
3072                            if (index as u32).wrapping_sub(1) < {
3073                                table.as_ptr().as_ref().unwrap_unchecked().size_array as u32
3074                            } && {
3075                                table
3076                                    .as_ptr()
3077                                    .as_ref()
3078                                    .unwrap_unchecked()
3079                                    .metatable
3080                                    .is_null()
3081                            } && { table.as_ptr().as_ref().unwrap_unchecked().readonly == 0 }
3082                                && (index as f64) == indexd
3083                            {
3084                                table.array_slot((index - 1) as usize).set_obj(ra);
3085                                if ra.is_collectable() {
3086                                    let table_object: GcObject = table.into();
3087                                    let child = ra.gc_value();
3088                                    if table_object.is_black() && child.is_white() {
3089                                        thread.barrier_table(table, child);
3090                                    }
3091                                }
3092                            } else {
3093                                thread.set_vm_saved_pc(pc);
3094                                thread.set_table_internal(rb, rc, ra)?;
3095                                base = thread.stack_base();
3096                            }
3097                        } else {
3098                            thread.set_vm_saved_pc(pc);
3099                            thread.set_table_internal(rb, rc, ra)?;
3100                            base = thread.stack_base();
3101                        }
3102                    }
3103                    Opcode::GetTableN => {
3104                        let ra_cursor =
3105                            base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
3106                        let ra = ra_cursor.value_unchecked();
3107                        let rb = base
3108                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3109                            .value_unchecked();
3110                        let c = instruction.c() as i32;
3111
3112                        if rb.is_table() {
3113                            let table = { rb.table_value() };
3114                            if (c as u32) < {
3115                                table.as_ptr().as_ref().unwrap_unchecked().size_array as u32
3116                            } && {
3117                                table
3118                                    .as_ptr()
3119                                    .as_ref()
3120                                    .unwrap_unchecked()
3121                                    .metatable
3122                                    .is_null()
3123                            } {
3124                                ra.set_obj(table.array_slot(c as usize));
3125                            } else {
3126                                let mut number_raw = RawTValue::number((c + 1) as f64);
3127                                let number = TValue::from_mut(&mut number_raw);
3128                                thread.set_vm_saved_pc(pc);
3129                                thread.get_table_internal(rb, number, ra_cursor)?;
3130                                base = thread.stack_base();
3131                            }
3132                        } else {
3133                            let mut number_raw = RawTValue::number((c + 1) as f64);
3134                            let number = TValue::from_mut(&mut number_raw);
3135                            thread.set_vm_saved_pc(pc);
3136                            thread.get_table_internal(rb, number, ra_cursor)?;
3137                            base = thread.stack_base();
3138                        }
3139                    }
3140                    Opcode::SetTableN => {
3141                        let ra = base
3142                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
3143                            .value_unchecked();
3144                        let rb = base
3145                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3146                            .value_unchecked();
3147                        let c = instruction.c() as i32;
3148
3149                        if rb.is_table() {
3150                            let table = { rb.table_value() };
3151                            if (c as u32) < {
3152                                table.as_ptr().as_ref().unwrap_unchecked().size_array as u32
3153                            } && {
3154                                table
3155                                    .as_ptr()
3156                                    .as_ref()
3157                                    .unwrap_unchecked()
3158                                    .metatable
3159                                    .is_null()
3160                            } && { table.as_ptr().as_ref().unwrap_unchecked().readonly == 0 }
3161                            {
3162                                table.array_slot(c as usize).set_obj(ra);
3163                                if ra.is_collectable() {
3164                                    let table_object: GcObject = table.into();
3165                                    let child = ra.gc_value();
3166                                    if table_object.is_black() && child.is_white() {
3167                                        thread.barrier_table(table, child);
3168                                    }
3169                                }
3170                            } else {
3171                                let mut number_raw = RawTValue::number((c + 1) as f64);
3172                                let number = TValue::from_mut(&mut number_raw);
3173                                thread.set_vm_saved_pc(pc);
3174                                thread.set_table_internal(rb, number, ra)?;
3175                                base = thread.stack_base();
3176                            }
3177                        } else {
3178                            let mut number_raw = RawTValue::number((c + 1) as f64);
3179                            let number = TValue::from_mut(&mut number_raw);
3180                            thread.set_vm_saved_pc(pc);
3181                            thread.set_table_internal(rb, number, ra)?;
3182                            base = thread.stack_base();
3183                        }
3184                    }
3185                    Opcode::NameCall => {
3186                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
3187                        let ra_value = ra.value_unchecked();
3188                        let rb = base
3189                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3190                            .value_unchecked();
3191                        let aux = { InstructionAux::new((*pc).word()) };
3192                        pc = pc.add(1);
3193                        let kv = proto.vm_const(constants, aux.word() as usize);
3194                        debug_assert!({ kv.is_string() });
3195                        let kv_string = { kv.string_value() };
3196
3197                        if rb.is_table() {
3198                            let table = { rb.table_value() };
3199                            let slot = {
3200                                kv_string.as_ptr().as_ref().unwrap_unchecked().hash as usize
3201                                    & table.hash_mask()
3202                            };
3203                            let node = { table.node(slot as i32) };
3204
3205                            if node.has_string_key(kv_string) && !node.value_is_nil() {
3206                                ra.add(1).value_unchecked().set_obj(rb);
3207                                ra_value.set_obj(node.value_unchecked());
3208                            } else if node.next() == 0 {
3209                                if let Some(index_tm) =
3210                                    thread.fast_tm(table.metatable(), TmEvent::Index)
3211                                    && index_tm.is_table()
3212                                {
3213                                    let meta_table = { index_tm.table_value() };
3214                                    let meta_slot =
3215                                        instruction.c() as usize & meta_table.node_mask_8();
3216                                    let meta_node = { meta_table.node(meta_slot as i32) };
3217
3218                                    if meta_node.has_string_key(kv_string)
3219                                        && !meta_node.value_is_nil()
3220                                    {
3221                                        ra.add(1).value_unchecked().set_obj(rb);
3222                                        ra_value.set_obj(meta_node.value_unchecked());
3223                                        break 'dispatch;
3224                                    }
3225                                }
3226
3227                                {
3228                                    ra.add(1).value_unchecked().set_obj(rb);
3229                                    thread.set_cached_slot(i32::from(instruction.c()));
3230                                }
3231                                thread.set_vm_saved_pc(pc);
3232                                thread.get_table_internal(rb, kv, ra)?;
3233                                let cached_slot = thread.cached_slot();
3234                                patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
3235                                base = thread.stack_base();
3236                                let ra = base
3237                                    .vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
3238                                if ra.value_unchecked().is_nil() {
3239                                    return thread
3240                                        .method_error(ra.add(1).value_unchecked(), kv_string)
3241                                        .map_err(Into::into);
3242                                }
3243                            } else {
3244                                {
3245                                    ra.add(1).value_unchecked().set_obj(rb);
3246                                    thread.set_cached_slot(i32::from(instruction.c()));
3247                                }
3248                                thread.set_vm_saved_pc(pc);
3249                                thread.get_table_internal(rb, kv, ra)?;
3250                                let cached_slot = thread.cached_slot();
3251                                patch_instruction_c(insn_pc as *mut Instruction, cached_slot as u8);
3252                                base = thread.stack_base();
3253                                let ra = base
3254                                    .vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
3255                                if ra.value_unchecked().is_nil() {
3256                                    return thread
3257                                        .method_error(ra.add(1).value_unchecked(), kv_string)
3258                                        .map_err(Into::into);
3259                                }
3260                            }
3261                        } else {
3262                            let metatable = if rb.is_userdata() {
3263                                rb.userdata_value().metatable()
3264                            } else {
3265                                global.metatable(rb.tt() as usize)
3266                            };
3267
3268                            if let Some(function) = thread.fast_tm(metatable, TmEvent::NameCall) {
3269                                {
3270                                    ra.add(1).value_unchecked().set_obj(rb);
3271                                    ra_value.set_obj(function);
3272                                    thread.set_name_call(Some(kv_string));
3273                                }
3274                            } else if let Some(index_tm) = thread.fast_tm(metatable, TmEvent::Index)
3275                            {
3276                                if index_tm.is_table() {
3277                                    let table = { index_tm.table_value() };
3278                                    let slot = instruction.c() as usize & table.node_mask_8();
3279                                    let node = { table.node(slot as i32) };
3280
3281                                    if node.has_string_key(kv_string) && !node.value_is_nil() {
3282                                        ra.add(1).value_unchecked().set_obj(rb);
3283                                        ra_value.set_obj(node.value_unchecked());
3284                                    } else {
3285                                        {
3286                                            ra.add(1).value_unchecked().set_obj(rb);
3287                                            thread.set_cached_slot(slot as i32);
3288                                        }
3289                                        thread.set_vm_saved_pc(pc);
3290                                        thread.get_table_internal(rb, kv, ra)?;
3291                                        let cached_slot = thread.cached_slot();
3292                                        patch_instruction_c(
3293                                            insn_pc as *mut Instruction,
3294                                            cached_slot as u8,
3295                                        );
3296                                        base = thread.stack_base();
3297                                        let ra = base.vm_reg_cursor(
3298                                            thread.stack_top(),
3299                                            instruction.a() as usize,
3300                                        );
3301                                        if ra.value_unchecked().is_nil() {
3302                                            return thread
3303                                                .method_error(
3304                                                    ra.add(1).value_unchecked(),
3305                                                    kv_string,
3306                                                )
3307                                                .map_err(Into::into);
3308                                        }
3309                                    }
3310                                } else if flags::DebugLuauUserDefinedClassesRuntime.get() && {
3311                                    rb.is_object()
3312                                } {
3313                                    let instance = { rb.object_value() };
3314                                    ra.add(1).value_unchecked().set_obj(rb);
3315                                    match instance.lookup_member_cached(kv_string, instruction.c())
3316                                    {
3317                                        ObjectMemberLookup::Cached(member) => {
3318                                            ra_value.set_obj(member);
3319                                        }
3320                                        ObjectMemberLookup::Resolved { offset, member } => {
3321                                            ra_value.set_obj(member);
3322                                            patch_instruction_c(
3323                                                insn_pc as *mut Instruction,
3324                                                offset as u8,
3325                                            );
3326                                        }
3327                                        ObjectMemberLookup::Missing => {
3328                                            return thread
3329                                                .missing_member_error(rb, kv)
3330                                                .map_err(Into::into);
3331                                        }
3332                                    }
3333                                } else {
3334                                    {
3335                                        ra.add(1).value_unchecked().set_obj(rb);
3336                                    }
3337                                    thread.set_vm_saved_pc(pc);
3338                                    thread.get_table_internal(rb, kv, ra)?;
3339                                    base = thread.stack_base();
3340                                    let ra = base.vm_reg_cursor(
3341                                        thread.stack_top(),
3342                                        instruction.a() as usize,
3343                                    );
3344                                    if ra.value_unchecked().is_nil() {
3345                                        return thread
3346                                            .method_error(ra.add(1).value_unchecked(), kv_string)
3347                                            .map_err(Into::into);
3348                                    }
3349                                }
3350                            } else if flags::DebugLuauUserDefinedClassesRuntime.get() && {
3351                                rb.is_object()
3352                            } {
3353                                let instance = { rb.object_value() };
3354                                ra.add(1).value_unchecked().set_obj(rb);
3355                                match instance.lookup_member_cached(kv_string, instruction.c()) {
3356                                    ObjectMemberLookup::Cached(member) => {
3357                                        ra_value.set_obj(member);
3358                                    }
3359                                    ObjectMemberLookup::Resolved { offset, member } => {
3360                                        ra_value.set_obj(member);
3361                                        patch_instruction_c(
3362                                            insn_pc as *mut Instruction,
3363                                            offset as u8,
3364                                        );
3365                                    }
3366                                    ObjectMemberLookup::Missing => {
3367                                        return thread
3368                                            .missing_member_error(rb, kv)
3369                                            .map_err(Into::into);
3370                                    }
3371                                }
3372                            } else {
3373                                {
3374                                    ra.add(1).value_unchecked().set_obj(rb);
3375                                }
3376                                thread.set_vm_saved_pc(pc);
3377                                thread.get_table_internal(rb, kv, ra)?;
3378                                base = thread.stack_base();
3379                                let ra = base
3380                                    .vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
3381                                if ra.value_unchecked().is_nil() {
3382                                    return thread
3383                                        .method_error(ra.add(1).value_unchecked(), kv_string)
3384                                        .map_err(Into::into);
3385                                }
3386                            }
3387                        }
3388
3389                        #[cfg(debug_assertions)]
3390                        if !flags::LuauCallFeedback.get() {
3391                            assert_ne!((*pc).opcode(), Opcode::CallFb);
3392                        }
3393                    }
3394                    Opcode::GetUDataKs => {
3395                        let _ra = base
3396                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
3397                            .value_unchecked();
3398                        let rb = base
3399                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3400                            .value_unchecked();
3401                        let aux = { (*pc).word() };
3402                        pc = pc.add(1);
3403                        let kidx = (aux & 0xffff) as usize;
3404                        let kv = proto.vm_const(constants, kidx);
3405
3406                        if rb.is_userdata() {
3407                            let userdata = { rb.userdata_value() };
3408                            let utag =
3409                                { userdata.as_ptr().as_ref().unwrap_unchecked().tag as usize };
3410                            let direct = {
3411                                &global.as_ptr().as_ref().unwrap_unchecked().userdata_direct[utag]
3412                            };
3413                            let function = direct.index;
3414                            let tm = TValue::from_ref(&direct.index_tm);
3415
3416                            if let Some(function) = function
3417                                && !tm.is_nil()
3418                            {
3419                                let udata = { userdata.data_mut_ptr() };
3420                                let top_cursor = thread.stack_top();
3421                                debug_assert!({
3422                                    top_cursor.add(3)
3423                                        < thread.stack().add(
3424                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
3425                                                as usize,
3426                                        )
3427                                });
3428                                {
3429                                    top_cursor.value_unchecked().set_obj(tm);
3430                                    top_cursor.add(1).value_unchecked().set_obj(rb);
3431                                    top_cursor.add(2).value_unchecked().set_obj(kv);
3432                                    thread.set_stack_top(top_cursor.add(3));
3433                                }
3434
3435                                thread.set_vm_saved_pc(pc);
3436                                {
3437                                    thread.increment_native_call_depth();
3438                                }
3439                                if thread
3440                                    .as_ptr()
3441                                    .as_ref()
3442                                    .unwrap_unchecked()
3443                                    .native_call_depth
3444                                    >= crate::thread::LUAI_MAX_NATIVE_CALLS
3445                                {
3446                                    thread.check_c_stack()?;
3447                                }
3448
3449                                thread.setup_cci(1, top_cursor)?;
3450
3451                                let mut cached_slot = (aux >> 16) as u16;
3452                                {
3453                                    function(
3454                                        thread,
3455                                        udata.cast(),
3456                                        i32::from(
3457                                            kv.string_value()
3458                                                .as_ptr()
3459                                                .as_ref()
3460                                                .unwrap_unchecked()
3461                                                .atom,
3462                                        ),
3463                                        &mut cached_slot,
3464                                        utag as i32,
3465                                    )?;
3466                                }
3467
3468                                if cached_slot != (aux >> 16) as u16
3469                                    && decode_instruction_opcode(*insn_pc) == Opcode::GetUDataKs
3470                                {
3471                                    patch_aux_slot(
3472                                        pc.sub(1) as *mut Instruction,
3473                                        kidx as u16,
3474                                        cached_slot,
3475                                    );
3476                                }
3477
3478                                let parent_cursor = thread.current_call_info_cursor().sub(1);
3479                                let parent = parent_cursor.call_info_unchecked();
3480
3481                                {
3482                                    thread.set_current_call_info(parent_cursor);
3483                                    thread.set_stack_base(parent.base());
3484                                    thread.decrement_native_call_depth();
3485                                }
3486
3487                                base = thread.stack_base();
3488                                let ra = base
3489                                    .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
3490                                    .value_unchecked();
3491                                {
3492                                    let result_cursor = thread.stack_top().sub(1);
3493                                    ra.set_obj(result_cursor.value_unchecked());
3494                                    thread.set_stack_top(parent.top());
3495                                }
3496                                break 'dispatch;
3497                            }
3498                        }
3499
3500                        patch_instruction_opcode(insn_pc as *mut Instruction, Opcode::GetTableKs);
3501                        patch_aux_slot(pc.sub(1) as *mut Instruction, kidx as u16, 0);
3502                        pc = insn_pc.add(1);
3503                        dispatch_opcode = Opcode::GetTableKs;
3504                        continue 'dispatch;
3505                    }
3506                    Opcode::SetUDataKs => {
3507                        let ra = base
3508                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
3509                            .value_unchecked();
3510                        let rb = base
3511                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3512                            .value_unchecked();
3513                        let aux = { (*pc).word() };
3514                        pc = pc.add(1);
3515                        let kidx = (aux & 0xffff) as usize;
3516                        let kv = proto.vm_const(constants, kidx);
3517
3518                        if rb.is_userdata() {
3519                            let userdata = { rb.userdata_value() };
3520                            let utag =
3521                                { userdata.as_ptr().as_ref().unwrap_unchecked().tag as usize };
3522                            let direct = {
3523                                &global.as_ptr().as_ref().unwrap_unchecked().userdata_direct[utag]
3524                            };
3525                            let function = direct.new_index;
3526                            let tm = TValue::from_ref(&direct.new_index_tm);
3527
3528                            if let Some(function) = function
3529                                && !tm.is_nil()
3530                            {
3531                                let udata = { userdata.data_mut_ptr() };
3532                                let top_cursor = thread.stack_top();
3533                                debug_assert!({
3534                                    top_cursor.add(4)
3535                                        < thread.stack().add(
3536                                            thread.as_ptr().as_ref().unwrap_unchecked().stack_size
3537                                                as usize,
3538                                        )
3539                                });
3540                                {
3541                                    top_cursor.value_unchecked().set_obj(tm);
3542                                    top_cursor.add(1).value_unchecked().set_obj(rb);
3543                                    top_cursor.add(2).value_unchecked().set_obj(kv);
3544                                    top_cursor.add(3).value_unchecked().set_obj(ra);
3545                                    thread.set_stack_top(top_cursor.add(4));
3546                                }
3547
3548                                thread.set_vm_saved_pc(pc);
3549                                {
3550                                    thread.increment_native_call_depth();
3551                                }
3552                                if thread
3553                                    .as_ptr()
3554                                    .as_ref()
3555                                    .unwrap_unchecked()
3556                                    .native_call_depth
3557                                    >= crate::thread::LUAI_MAX_NATIVE_CALLS
3558                                {
3559                                    thread.check_c_stack()?;
3560                                }
3561
3562                                thread.setup_cci(0, top_cursor)?;
3563
3564                                let mut cached_slot = (aux >> 16) as u16;
3565                                {
3566                                    function(
3567                                        thread,
3568                                        udata.cast(),
3569                                        i32::from(
3570                                            kv.string_value()
3571                                                .as_ptr()
3572                                                .as_ref()
3573                                                .unwrap_unchecked()
3574                                                .atom,
3575                                        ),
3576                                        &mut cached_slot,
3577                                        utag as i32,
3578                                    )?;
3579                                }
3580
3581                                if cached_slot != (aux >> 16) as u16
3582                                    && decode_instruction_opcode(*insn_pc) == Opcode::SetUDataKs
3583                                {
3584                                    patch_aux_slot(
3585                                        pc.sub(1) as *mut Instruction,
3586                                        kidx as u16,
3587                                        cached_slot,
3588                                    );
3589                                }
3590
3591                                let parent = thread.current_call_info_cursor().sub(1);
3592
3593                                {
3594                                    let parent_call_info = parent.call_info_unchecked();
3595                                    thread.set_current_call_info(parent);
3596                                    thread.set_stack_base(parent_call_info.base());
3597                                    thread.set_stack_top(parent_call_info.top());
3598                                    thread.decrement_native_call_depth();
3599                                }
3600                                base = thread.stack_base();
3601                                break 'dispatch;
3602                            }
3603                        }
3604
3605                        patch_instruction_opcode(insn_pc as *mut Instruction, Opcode::SetTableKs);
3606                        patch_aux_slot(pc.sub(1) as *mut Instruction, kidx as u16, 0);
3607                        pc = insn_pc.add(1);
3608                        dispatch_opcode = Opcode::SetTableKs;
3609                        continue 'dispatch;
3610                    }
3611                    Opcode::NameCallUData => {
3612                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
3613                        let ra_value = ra.value_unchecked();
3614                        let rb = base
3615                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3616                            .value_unchecked();
3617                        let aux = { (*pc).word() };
3618                        let namecall_slot = pc;
3619                        pc = pc.add(1);
3620                        let kidx = (aux & 0xffff) as usize;
3621                        let kv = proto.vm_const(constants, kidx);
3622
3623                        if rb.is_userdata() {
3624                            let userdata = { rb.userdata_value() };
3625                            let utag =
3626                                { userdata.as_ptr().as_ref().unwrap_unchecked().tag as usize };
3627                            let direct = {
3628                                &global.as_ptr().as_ref().unwrap_unchecked().userdata_direct[utag]
3629                            };
3630                            let function = direct.name_call;
3631                            let tm = TValue::from_ref(&direct.name_call_tm);
3632
3633                            if let Some(function) = function
3634                                && !tm.is_nil()
3635                            {
3636                                let udata = { userdata.data_mut_ptr() };
3637                                {
3638                                    ra.add(1).value_unchecked().set_obj(rb);
3639                                    ra_value.set_obj(tm);
3640                                }
3641
3642                                debug_assert!(matches!(
3643                                    { (*pc).opcode() },
3644                                    Opcode::Call | Opcode::CallFb
3645                                ));
3646                                let call_instruction = { *pc };
3647                                pc = pc.add(1);
3648                                if flags::LuauCallFeedback.get()
3649                                    && call_instruction.opcode() == Opcode::CallFb
3650                                {
3651                                    pc = pc.add(1);
3652                                }
3653
3654                                let call_ra = base.vm_reg_cursor(
3655                                    thread.stack_top(),
3656                                    call_instruction.a() as usize,
3657                                );
3658                                debug_assert!(call_ra == ra);
3659
3660                                let n_params = i32::from(call_instruction.b()) - 1;
3661                                let n_results = i32::from(call_instruction.c()) - 1;
3662
3663                                thread.set_vm_saved_pc(pc);
3664                                {
3665                                    thread.set_name_call(Some(kv.string_value()));
3666                                    let top = thread.stack_top();
3667                                    thread.set_stack_top(if n_params == LUA_MULTRET {
3668                                        top
3669                                    } else {
3670                                        ra.add(1 + n_params as usize)
3671                                    });
3672                                }
3673
3674                                thread.setup_cci(n_results, ra)?;
3675
3676                                let mut cached_slot = (aux >> 16) as u16;
3677                                debug_assert!({
3678                                    kv.string_value().as_ptr().as_ref().unwrap_unchecked().atom >= 0
3679                                });
3680                                let namecall_result = {
3681                                    function(
3682                                        thread,
3683                                        udata.cast(),
3684                                        i32::from(
3685                                            kv.string_value()
3686                                                .as_ptr()
3687                                                .as_ref()
3688                                                .unwrap_unchecked()
3689                                                .atom,
3690                                        ),
3691                                        &mut cached_slot,
3692                                        utag as i32,
3693                                    )
3694                                };
3695
3696                                if matches!(namecall_result, Ok(_) | Err(VmExit::Control(_)))
3697                                    && cached_slot != (aux >> 16) as u16
3698                                    && decode_instruction_opcode(*insn_pc) == Opcode::NameCallUData
3699                                {
3700                                    patch_aux_slot(
3701                                        namecall_slot as *mut Instruction,
3702                                        kidx as u16,
3703                                        cached_slot,
3704                                    );
3705                                }
3706                                let results = namecall_result?;
3707
3708                                let call_info = thread.current_call_info();
3709                                let parent = thread.current_call_info_cursor().sub(1);
3710
3711                                let mut result_slot = { call_info.function() };
3712                                let mut value_iter = { thread.stack_top().sub(results) };
3713                                let value_end = { thread.stack_top() };
3714                                let mut remaining = n_results;
3715
3716                                while remaining != 0 && value_iter < value_end {
3717                                    result_slot
3718                                        .value_unchecked()
3719                                        .set_obj(value_iter.value_unchecked());
3720                                    result_slot = result_slot.add(1);
3721                                    value_iter = value_iter.add(1);
3722                                    remaining -= 1;
3723                                }
3724                                while remaining > 0 {
3725                                    result_slot.value_unchecked().set_nil();
3726                                    result_slot = result_slot.add(1);
3727                                    remaining -= 1;
3728                                }
3729
3730                                {
3731                                    let parent_call_info = parent.call_info_unchecked();
3732                                    thread.set_current_call_info(parent);
3733                                    thread.set_stack_base(parent_call_info.base());
3734                                    thread.set_stack_top(if n_results == LUA_MULTRET {
3735                                        result_slot
3736                                    } else {
3737                                        parent_call_info.top()
3738                                    });
3739                                }
3740                                base = thread.stack_base();
3741                                break 'dispatch;
3742                            }
3743                        }
3744
3745                        patch_instruction_opcode(insn_pc as *mut Instruction, Opcode::NameCall);
3746                        patch_aux_slot(namecall_slot as *mut Instruction, kidx as u16, 0);
3747                        pc = insn_pc.add(1);
3748                        dispatch_opcode = Opcode::NameCall;
3749                        continue 'dispatch;
3750                    }
3751                    Opcode::JumpX => {
3752                        thread.interrupt_vm(insn_pc)?;
3753                        base = thread.stack_base();
3754                        if flags::LuauBackedgeHeapCheck.get() && thread.needs_gc() {
3755                            thread.set_vm_saved_pc(pc);
3756                            thread.step(true)?;
3757                            base = thread.stack_base();
3758                        }
3759
3760                        pc = pc.offset(instruction.e() as isize);
3761                        proto.assert_vm_pc(pc);
3762                    }
3763                    Opcode::FastCall => {
3764                        let builtin_id = instruction.a();
3765                        let skip = instruction.c() as usize;
3766                        debug_assert!(
3767                            {
3768                                pc.offset_from(proto.as_ptr().as_ref().unwrap_unchecked().code)
3769                                    as usize
3770                            } + skip
3771                                < { proto.as_ptr().as_ref().unwrap_unchecked().size_code as usize }
3772                        );
3773
3774                        let call = { *pc.add(skip) };
3775                        debug_assert_eq!(call.opcode(), Opcode::Call);
3776
3777                        let ra = base.vm_reg_cursor(thread.stack_top(), call.a() as usize);
3778                        let mut nparams = i32::from(call.b()) - 1;
3779                        let nresults = i32::from(call.c()) - 1;
3780
3781                        if nparams == LUA_MULTRET {
3782                            nparams = thread.stack_top().offset_from(ra) as i32 - 1;
3783                        }
3784
3785                        let builtin = crate::builtins::LUAU_F_TABLE[builtin_id as usize];
3786                        let env = closure.env();
3787
3788                        if env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0 {
3789                            thread.set_vm_saved_pc(pc);
3790                            let produced = {
3791                                builtin(
3792                                    thread,
3793                                    ra,
3794                                    ra.add(1).value_unchecked(),
3795                                    nresults,
3796                                    ra.add(2),
3797                                    nparams,
3798                                )
3799                            };
3800
3801                            if produced >= 0 {
3802                                {
3803                                    thread.set_stack_top(if nresults == LUA_MULTRET {
3804                                        ra.add(produced as usize)
3805                                    } else {
3806                                        thread.current_call_info().top()
3807                                    });
3808                                }
3809
3810                                pc = pc.add(skip + 1);
3811                                proto.assert_vm_pc(pc);
3812                            }
3813                        }
3814                    }
3815                    Opcode::Coverage => {
3816                        let hits = instruction.e();
3817                        let patched_hits = if hits < (1 << 23) - 1 { hits + 1 } else { hits };
3818                        let patched = Instruction::ae(Opcode::Coverage, patched_hits);
3819                        {
3820                            *(insn_pc as *mut Instruction) = patched;
3821                        }
3822                    }
3823                    Opcode::Capture => {
3824                        unreachable!(
3825                            "CAPTURE is a pseudo-opcode and must execute as part of closure creation"
3826                        );
3827                    }
3828                    Opcode::FastCall1 => {
3829                        let builtin_id = instruction.a();
3830                        let arg = base
3831                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3832                            .value_unchecked();
3833                        let skip = instruction.c() as usize;
3834                        debug_assert!(
3835                            {
3836                                pc.offset_from(proto.as_ptr().as_ref().unwrap_unchecked().code)
3837                                    as usize
3838                            } + skip
3839                                < { proto.as_ptr().as_ref().unwrap_unchecked().size_code as usize }
3840                        );
3841
3842                        let call = { *pc.add(skip) };
3843                        debug_assert_eq!(call.opcode(), Opcode::Call);
3844
3845                        let ra = base.vm_reg_cursor(thread.stack_top(), call.a() as usize);
3846                        let _ra_value = ra.value_unchecked();
3847                        let nresults = i32::from(call.c()) - 1;
3848                        let builtin = crate::builtins::LUAU_F_TABLE[builtin_id as usize];
3849                        let env = closure.env();
3850
3851                        if env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0 {
3852                            thread.set_vm_saved_pc(pc);
3853                            let produced = { builtin(thread, ra, arg, nresults, ra.add(1), 1) };
3854
3855                            if produced >= 0 {
3856                                if nresults == LUA_MULTRET {
3857                                    {
3858                                        thread.set_stack_top(ra.add(produced as usize));
3859                                    }
3860                                }
3861
3862                                pc = pc.add(skip + 1);
3863                                proto.assert_vm_pc(pc);
3864                            }
3865                        }
3866                    }
3867                    Opcode::FastCall2 => {
3868                        let skip = instruction.c() as usize - 1;
3869                        let aux = { InstructionAux::new((*pc).word()) };
3870                        pc = pc.add(1);
3871
3872                        let builtin_id = instruction.a();
3873                        let arg1 = base
3874                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3875                            .value_unchecked();
3876                        let arg2 = base.vm_reg_cursor(thread.stack_top(), aux.word() as usize);
3877
3878                        debug_assert!(
3879                            {
3880                                pc.offset_from(proto.as_ptr().as_ref().unwrap_unchecked().code)
3881                                    as usize
3882                            } + skip
3883                                < { proto.as_ptr().as_ref().unwrap_unchecked().size_code as usize }
3884                        );
3885
3886                        let call = { *pc.add(skip) };
3887                        debug_assert_eq!(call.opcode(), Opcode::Call);
3888
3889                        let ra = base.vm_reg_cursor(thread.stack_top(), call.a() as usize);
3890                        let nresults = i32::from(call.c()) - 1;
3891                        let builtin = crate::builtins::LUAU_F_TABLE[builtin_id as usize];
3892                        let env = closure.env();
3893
3894                        if env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0 {
3895                            thread.set_vm_saved_pc(pc);
3896                            let produced = { builtin(thread, ra, arg1, nresults, arg2, 2) };
3897
3898                            if produced >= 0 {
3899                                if nresults == LUA_MULTRET {
3900                                    {
3901                                        thread.set_stack_top(ra.add(produced as usize));
3902                                    }
3903                                }
3904
3905                                pc = pc.add(skip + 1);
3906                                proto.assert_vm_pc(pc);
3907                            }
3908                        }
3909                    }
3910                    Opcode::FastCall2K => {
3911                        let skip = instruction.c() as usize - 1;
3912                        let aux = { InstructionAux::new((*pc).word()) };
3913                        pc = pc.add(1);
3914
3915                        let builtin_id = instruction.a();
3916                        let arg1 = base
3917                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3918                            .value_unchecked();
3919                        let arg2 = constants.add(aux.word() as usize);
3920
3921                        debug_assert!(
3922                            {
3923                                pc.offset_from(proto.as_ptr().as_ref().unwrap_unchecked().code)
3924                                    as usize
3925                            } + skip
3926                                < { proto.as_ptr().as_ref().unwrap_unchecked().size_code as usize }
3927                        );
3928
3929                        let call = { *pc.add(skip) };
3930                        debug_assert_eq!(call.opcode(), Opcode::Call);
3931
3932                        let ra = base.vm_reg_cursor(thread.stack_top(), call.a() as usize);
3933                        let nresults = i32::from(call.c()) - 1;
3934                        let builtin = crate::builtins::LUAU_F_TABLE[builtin_id as usize];
3935                        let env = closure.env();
3936
3937                        if env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0 {
3938                            thread.set_vm_saved_pc(pc);
3939                            let produced = { builtin(thread, ra, arg1, nresults, arg2, 2) };
3940
3941                            if produced >= 0 {
3942                                if nresults == LUA_MULTRET {
3943                                    {
3944                                        thread.set_stack_top(ra.add(produced as usize));
3945                                    }
3946                                }
3947
3948                                pc = pc.add(skip + 1);
3949                                proto.assert_vm_pc(pc);
3950                            }
3951                        }
3952                    }
3953                    Opcode::FastCall3 => {
3954                        let skip = instruction.c() as usize - 1;
3955                        let aux = { InstructionAux::new((*pc).word()) };
3956                        pc = pc.add(1);
3957
3958                        let builtin_id = instruction.a();
3959                        let arg1 = base
3960                            .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
3961                            .value_unchecked();
3962                        let arg2 = base
3963                            .vm_reg_cursor(thread.stack_top(), aux.a() as usize)
3964                            .value_unchecked();
3965                        let arg3 = base
3966                            .vm_reg_cursor(thread.stack_top(), aux.b() as usize)
3967                            .value_unchecked();
3968
3969                        debug_assert!(
3970                            {
3971                                pc.offset_from(proto.as_ptr().as_ref().unwrap_unchecked().code)
3972                                    as usize
3973                            } + skip
3974                                < { proto.as_ptr().as_ref().unwrap_unchecked().size_code as usize }
3975                        );
3976
3977                        let call = { *pc.add(skip) };
3978                        debug_assert_eq!(call.opcode(), Opcode::Call);
3979
3980                        let ra = base.vm_reg_cursor(thread.stack_top(), call.a() as usize);
3981                        let nresults = i32::from(call.c()) - 1;
3982                        let builtin = crate::builtins::LUAU_F_TABLE[builtin_id as usize];
3983                        let env = closure.env();
3984
3985                        if env.as_ptr().as_ref().unwrap_unchecked().safe_env != 0 {
3986                            thread.set_vm_saved_pc(pc);
3987                            debug_assert!(
3988                                thread.stack_top().add(2)
3989                                    < thread.stack().add(
3990                                        thread.as_ptr().as_ref().unwrap_unchecked().stack_size
3991                                            as usize
3992                                    )
3993                            );
3994                            let top_value = thread.stack_top();
3995                            {
3996                                top_value.value_unchecked().set_obj(arg2);
3997                                top_value.add(1).value_unchecked().set_obj(arg3);
3998                            }
3999
4000                            let produced = { builtin(thread, ra, arg1, nresults, top_value, 3) };
4001
4002                            if produced >= 0 {
4003                                if nresults == LUA_MULTRET {
4004                                    {
4005                                        thread.set_stack_top(ra.add(produced as usize));
4006                                    }
4007                                }
4008
4009                                pc = pc.add(skip + 1);
4010                                proto.assert_vm_pc(pc);
4011                            }
4012                        }
4013                    }
4014                    Opcode::Call => {
4015                        thread.interrupt_vm(insn_pc)?;
4016                        base = thread.stack_base();
4017
4018                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
4019                        let ra_value = ra.value_unchecked();
4020                        let nparams = i32::from(instruction.b()) - 1;
4021                        let nresults = i32::from(instruction.c()) - 1;
4022
4023                        let mut arg_top = { thread.stack_top() };
4024                        if nparams != LUA_MULTRET {
4025                            arg_top = ra.add(1 + nparams as usize);
4026                        }
4027
4028                        if !ra_value.is_function() {
4029                            thread.set_vm_saved_pc(pc);
4030                            thread.try_func_tm(ra)?;
4031                            arg_top = arg_top.add(1);
4032                        }
4033
4034                        let called_closure = { ra.value_unchecked().closure_value() };
4035                        thread.set_vm_saved_pc(pc);
4036
4037                        let call_info = thread.incr_ci()?.call_info_unchecked();
4038                        {
4039                            call_info.init_call(
4040                                ra,
4041                                arg_top.add(
4042                                    called_closure
4043                                        .as_ptr()
4044                                        .as_ref()
4045                                        .unwrap_unchecked()
4046                                        .stack_size as usize,
4047                                ),
4048                                nresults,
4049                                called_closure.proto(),
4050                            );
4051                        }
4052
4053                        {
4054                            thread.set_stack_base(call_info.base());
4055                            thread.set_stack_top(arg_top);
4056                        }
4057
4058                        thread.check_stack_for_new_ci(
4059                            called_closure
4060                                .as_ptr()
4061                                .as_ref()
4062                                .unwrap_unchecked()
4063                                .stack_size as i32,
4064                        )?;
4065                        debug_assert!(call_info.top() <= thread.stack_last());
4066
4067                        if called_closure.is_lua() {
4068                            let called_proto = { called_closure.proto().unwrap_unchecked() };
4069
4070                            {
4071                                let mut arg_cursor = thread.stack_top();
4072                                let arg_end_cursor = thread.stack_base().add(
4073                                    called_proto.as_ptr().as_ref().unwrap_unchecked().num_params
4074                                        as usize,
4075                                );
4076                                while arg_cursor < arg_end_cursor {
4077                                    arg_cursor.value_unchecked().set_nil();
4078                                    arg_cursor = arg_cursor.add(1);
4079                                }
4080
4081                                thread.set_stack_top(
4082                                    if called_proto.as_ptr().as_ref().unwrap_unchecked().is_vararg
4083                                        != 0
4084                                    {
4085                                        arg_cursor
4086                                    } else {
4087                                        call_info.top()
4088                                    },
4089                                );
4090
4091                                call_info.set_saved_pc(
4092                                    called_proto
4093                                        .as_ptr()
4094                                        .as_ref()
4095                                        .unwrap_unchecked()
4096                                        .code
4097                                        .cast_const(),
4098                                );
4099
4100                                if called_proto
4101                                    .as_ptr()
4102                                    .as_ref()
4103                                    .unwrap_unchecked()
4104                                    .exec_target
4105                                    != 0
4106                                    && !called_proto
4107                                        .as_ptr()
4108                                        .as_ref()
4109                                        .unwrap_unchecked()
4110                                        .exec_data
4111                                        .is_null()
4112                                {
4113                                    call_info.as_ptr().as_mut().unwrap_unchecked().flags =
4114                                        LUA_CALLINFO_NATIVE;
4115                                }
4116                            }
4117
4118                            pc = if thread.as_ptr().as_ref().unwrap_unchecked().single_step {
4119                                called_proto
4120                                    .as_ptr()
4121                                    .as_ref()
4122                                    .unwrap_unchecked()
4123                                    .code
4124                                    .cast_const()
4125                            } else {
4126                                called_proto.as_ptr().as_ref().unwrap_unchecked().code_entry
4127                            };
4128                            closure = called_closure;
4129                            base = thread.stack_base();
4130                            proto = called_proto;
4131                            constants = called_proto.constants();
4132                            if pc == {
4133                                called_proto.as_ptr().as_ref().unwrap_unchecked().code_entry
4134                            } {
4135                                called_proto.assert_vm_pc(
4136                                    called_proto
4137                                        .as_ptr()
4138                                        .as_ref()
4139                                        .unwrap_unchecked()
4140                                        .code
4141                                        .cast_const(),
4142                                );
4143                            } else {
4144                                called_proto.assert_vm_pc(pc);
4145                            }
4146                        } else {
4147                            thread.finish_native_call(called_closure, nresults)?;
4148
4149                            base = thread.stack_base();
4150                        }
4151                    }
4152                    Opcode::CallFb => {
4153                        debug_assert!(flags::LuauCallFeedback.get());
4154                        thread.interrupt_vm(insn_pc)?;
4155                        base = thread.stack_base();
4156
4157                        let feedback_slot = { (*pc).word() };
4158                        pc = pc.add(1);
4159
4160                        let ra = base.vm_reg_cursor(thread.stack_top(), instruction.a() as usize);
4161                        let ra_value = ra.value_unchecked();
4162                        let nparams = i32::from(instruction.b()) - 1;
4163                        let nresults = i32::from(instruction.c()) - 1;
4164
4165                        let mut arg_top = { thread.stack_top() };
4166                        if nparams != LUA_MULTRET {
4167                            arg_top = ra.add(1 + nparams as usize);
4168                        }
4169
4170                        if !ra_value.is_function() {
4171                            if feedback_slot != u32::MAX {
4172                                {
4173                                    *(pc.sub(1) as *mut Instruction) = Instruction::new(u32::MAX);
4174                                }
4175                            }
4176
4177                            thread.set_vm_saved_pc(pc);
4178                            thread.try_func_tm(ra)?;
4179                            arg_top = arg_top.add(1);
4180                        }
4181
4182                        let called_closure = { ra.value_unchecked().closure_value() };
4183                        thread.set_vm_saved_pc(pc);
4184
4185                        let call_info = thread.incr_ci()?.call_info_unchecked();
4186                        {
4187                            call_info.init_call(
4188                                ra,
4189                                arg_top.add(
4190                                    called_closure
4191                                        .as_ptr()
4192                                        .as_ref()
4193                                        .unwrap_unchecked()
4194                                        .stack_size as usize,
4195                                ),
4196                                nresults,
4197                                called_closure.proto(),
4198                            );
4199                        }
4200
4201                        {
4202                            thread.set_stack_base(call_info.base());
4203                            thread.set_stack_top(arg_top);
4204                        }
4205
4206                        thread.check_stack_for_new_ci(
4207                            called_closure
4208                                .as_ptr()
4209                                .as_ref()
4210                                .unwrap_unchecked()
4211                                .stack_size as i32,
4212                        )?;
4213                        debug_assert!(call_info.top() <= thread.stack_last());
4214
4215                        if called_closure.is_lua() {
4216                            let called_proto = { called_closure.proto().unwrap_unchecked() };
4217
4218                            if feedback_slot != u32::MAX
4219                                && !thread.record_hit(closure, called_closure, feedback_slot)
4220                            {
4221                                {
4222                                    *(pc.sub(1) as *mut Instruction) = Instruction::new(u32::MAX);
4223                                }
4224                            }
4225
4226                            {
4227                                let mut arg_cursor = thread.stack_top();
4228                                let arg_end_cursor = thread.stack_base().add(
4229                                    called_proto.as_ptr().as_ref().unwrap_unchecked().num_params
4230                                        as usize,
4231                                );
4232                                while arg_cursor < arg_end_cursor {
4233                                    arg_cursor.value_unchecked().set_nil();
4234                                    arg_cursor = arg_cursor.add(1);
4235                                }
4236
4237                                thread.set_stack_top(
4238                                    if called_proto.as_ptr().as_ref().unwrap_unchecked().is_vararg
4239                                        != 0
4240                                    {
4241                                        arg_cursor
4242                                    } else {
4243                                        call_info.top()
4244                                    },
4245                                );
4246
4247                                call_info.set_saved_pc(
4248                                    called_proto
4249                                        .as_ptr()
4250                                        .as_ref()
4251                                        .unwrap_unchecked()
4252                                        .code
4253                                        .cast_const(),
4254                                );
4255
4256                                if called_proto
4257                                    .as_ptr()
4258                                    .as_ref()
4259                                    .unwrap_unchecked()
4260                                    .exec_target
4261                                    != 0
4262                                    && !called_proto
4263                                        .as_ptr()
4264                                        .as_ref()
4265                                        .unwrap_unchecked()
4266                                        .exec_data
4267                                        .is_null()
4268                                {
4269                                    call_info.as_ptr().as_mut().unwrap_unchecked().flags =
4270                                        LUA_CALLINFO_NATIVE;
4271                                }
4272                            }
4273
4274                            pc = if thread.as_ptr().as_ref().unwrap_unchecked().single_step {
4275                                called_proto
4276                                    .as_ptr()
4277                                    .as_ref()
4278                                    .unwrap_unchecked()
4279                                    .code
4280                                    .cast_const()
4281                            } else {
4282                                called_proto.as_ptr().as_ref().unwrap_unchecked().code_entry
4283                            };
4284                            closure = called_closure;
4285                            base = thread.stack_base();
4286                            proto = called_proto;
4287                            constants = called_proto.constants();
4288                            if pc == {
4289                                called_proto.as_ptr().as_ref().unwrap_unchecked().code_entry
4290                            } {
4291                                called_proto.assert_vm_pc(
4292                                    called_proto
4293                                        .as_ptr()
4294                                        .as_ref()
4295                                        .unwrap_unchecked()
4296                                        .code
4297                                        .cast_const(),
4298                                );
4299                            } else {
4300                                called_proto.assert_vm_pc(pc);
4301                            }
4302                        } else {
4303                            if feedback_slot != u32::MAX {
4304                                {
4305                                    *(pc.sub(1) as *mut Instruction) = Instruction::new(u32::MAX);
4306                                }
4307                            }
4308
4309                            thread.finish_native_call(called_closure, nresults)?;
4310
4311                            base = thread.stack_base();
4312                        }
4313                    }
4314                    Opcode::Return => {
4315                        thread.interrupt_vm(insn_pc)?;
4316                        base = thread.stack_base();
4317
4318                        let ra = { base.add(instruction.a() as usize) };
4319                        let b = i32::from(instruction.b()) - 1;
4320
4321                        let call_info = { thread.current_call_info() };
4322                        let parent_cursor = thread.current_call_info_cursor().sub(1);
4323                        let parent = parent_cursor.call_info_unchecked();
4324
4325                        {
4326                            let mut result = call_info.function();
4327                            let mut value = ra;
4328                            let value_end = if b == LUA_MULTRET {
4329                                thread.stack_top()
4330                            } else {
4331                                ra.add(b as usize)
4332                            };
4333                            let mut remaining =
4334                                call_info.as_ptr().as_ref().unwrap_unchecked().n_results;
4335
4336                            while remaining != 0 && value < value_end {
4337                                result.value_unchecked().set_obj(value.value_unchecked());
4338                                result = result.add(1);
4339                                value = value.add(1);
4340                                remaining -= 1;
4341                            }
4342
4343                            while remaining > 0 {
4344                                result.value_unchecked().set_nil();
4345                                result = result.add(1);
4346                                remaining -= 1;
4347                            }
4348
4349                            thread.set_current_call_info(parent_cursor);
4350                            thread.set_stack_base(parent.base());
4351                            thread.set_stack_top(
4352                                if call_info.as_ptr().as_ref().unwrap_unchecked().n_results
4353                                    == LUA_MULTRET
4354                                {
4355                                    result
4356                                } else {
4357                                    parent.top()
4358                                },
4359                            );
4360                        }
4361
4362                        if {
4363                            call_info.as_ptr().as_ref().unwrap_unchecked().flags
4364                                & crate::state::LUA_CALLINFO_RETURN
4365                        } != 0
4366                        {
4367                            return Ok(());
4368                        }
4369
4370                        let next_closure = { parent.function_closure() };
4371                        let next_proto = { next_closure.proto().unwrap_unchecked() };
4372
4373                        if {
4374                            parent.as_ptr().as_ref().unwrap_unchecked().flags & LUA_CALLINFO_NATIVE
4375                        } != 0
4376                            && !thread.as_ptr().as_ref().unwrap_unchecked().single_step
4377                        {
4378                            let Some(enter) = global.execution_enter() else {
4379                                unreachable!(
4380                                    "native lvmexecute requires an execution enter callback"
4381                                );
4382                            };
4383
4384                            if { enter(thread, next_proto) } == 0 {
4385                                return Ok(());
4386                            }
4387
4388                            let resumed_call = thread.current_call_info();
4389                            closure = resumed_call.function_closure();
4390                            proto = closure.proto().unwrap_unchecked();
4391                            pc = resumed_call.saved_pc();
4392                            base = thread.stack_base();
4393                            constants = proto.constants();
4394                            proto.assert_vm_pc(pc);
4395                        } else {
4396                            pc = parent.saved_pc();
4397                            closure = next_closure;
4398                            base = thread.stack_base();
4399                            proto = next_proto;
4400                            constants = proto.constants();
4401                            proto.assert_vm_pc(pc);
4402                        }
4403                    }
4404                    Opcode::JumpXEqKNil => {
4405                        let aux = { InstructionAux::new((*pc).word()) };
4406                        let ra = base
4407                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
4408                            .value_unchecked();
4409                        let condition = { ra.is_nil() } != aux.is_negated();
4410                        pc = if condition {
4411                            pc.offset(i32::from(instruction.d()) as isize)
4412                        } else {
4413                            pc.add(1)
4414                        };
4415                        proto.assert_vm_pc(pc);
4416                    }
4417                    Opcode::JumpXEqKB => {
4418                        let aux = { InstructionAux::new((*pc).word()) };
4419                        let ra = base
4420                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
4421                            .value_unchecked();
4422                        let condition =
4423                            { ra.is_boolean() && ra.boolean_value() == i32::from(aux.kb()) }
4424                                != aux.is_negated();
4425                        pc = if condition {
4426                            pc.offset(i32::from(instruction.d()) as isize)
4427                        } else {
4428                            pc.add(1)
4429                        };
4430                        proto.assert_vm_pc(pc);
4431                    }
4432                    Opcode::JumpXEqKN => {
4433                        let aux = { InstructionAux::new((*pc).word()) };
4434                        let ra = base
4435                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
4436                            .value_unchecked();
4437                        let kv = proto.vm_const(constants, aux.kv() as usize);
4438                        #[cfg(target_arch = "aarch64")]
4439                        {
4440                            if aux.is_negated() {
4441                                pc = if !ra.is_number() || ra.number_value() != kv.number_value() {
4442                                    pc.offset(i32::from(instruction.d()) as isize)
4443                                } else {
4444                                    pc.add(1)
4445                                };
4446                            } else {
4447                                pc = if ra.is_number() && ra.number_value() == kv.number_value() {
4448                                    pc.offset(i32::from(instruction.d()) as isize)
4449                                } else {
4450                                    pc.add(1)
4451                                };
4452                            }
4453                        }
4454                        #[cfg(not(target_arch = "aarch64"))]
4455                        {
4456                            let condition = (ra.is_number()
4457                                && ra.number_value() == kv.number_value())
4458                                != aux.is_negated();
4459                            pc = if condition {
4460                                pc.offset(i32::from(instruction.d()) as isize)
4461                            } else {
4462                                pc.add(1)
4463                            };
4464                        }
4465                        proto.assert_vm_pc(pc);
4466                    }
4467                    Opcode::JumpXEqKS => {
4468                        let aux = { InstructionAux::new((*pc).word()) };
4469                        let ra = base
4470                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
4471                            .value_unchecked();
4472                        let kv = proto.vm_const(constants, aux.kv() as usize);
4473                        debug_assert!({ kv.is_string() });
4474                        let condition = { ra.is_string() && ra.gc_value() == kv.gc_value() }
4475                            != aux.is_negated();
4476                        pc = if condition {
4477                            pc.offset(i32::from(instruction.d()) as isize)
4478                        } else {
4479                            pc.add(1)
4480                        };
4481                        proto.assert_vm_pc(pc);
4482                    }
4483                    Opcode::NewClassMember => {
4484                        let aux = { (*pc).word() };
4485                        pc = pc.add(1);
4486
4487                        let ra = base
4488                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
4489                            .value_unchecked();
4490                        let member_name = proto.vm_const(constants, aux as usize);
4491                        debug_assert!({ member_name.is_string() });
4492                        debug_assert_eq!(instruction.b(), 0);
4493                        let rc = base
4494                            .vm_reg_cursor(thread.stack_top(), instruction.c() as usize)
4495                            .value_unchecked();
4496                        thread.set_vm_saved_pc(pc);
4497                        { ra.class_value() }.add_class_member(
4498                            thread,
4499                            member_name.string_value(),
4500                            rc,
4501                        )?;
4502                    }
4503                    Opcode::NewClass => {
4504                        let aux = (*pc).word();
4505                        pc = pc.add(1);
4506
4507                        let ra = base
4508                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
4509                            .value_unchecked();
4510                        let class_shape = proto.vm_const(constants, aux as usize);
4511                        debug_assert!(class_shape.is_class());
4512                        ra.set_obj(class_shape);
4513
4514                        if instruction.b() != u8::MAX {
4515                            thread.set_vm_saved_pc(pc);
4516
4517                            let superclass = base
4518                                .vm_reg_cursor(thread.stack_top(), instruction.b() as usize)
4519                                .value_unchecked();
4520                            if !superclass.is_class() {
4521                                return thread.type_error(superclass, "extend").map_err(Into::into);
4522                            }
4523
4524                            let class = thread.inherit_class(
4525                                class_shape.class_value(),
4526                                superclass.class_value(),
4527                            )?;
4528                            ra.set_class_value(class);
4529                        }
4530                    }
4531                    Opcode::CmpProto => {
4532                        let fun_id = { (*pc).word() };
4533                        let ra = base
4534                            .vm_reg_cursor(thread.stack_top(), instruction.a() as usize)
4535                            .value_unchecked();
4536
4537                        let is_function = { ra.is_function() };
4538                        let should_jump = if !is_function {
4539                            true
4540                        } else {
4541                            let called = { ra.closure_value() };
4542                            if called.is_native() {
4543                                true
4544                            } else {
4545                                let called_proto = called.proto().unwrap_unchecked();
4546                                called_proto.as_ptr().as_ref().unwrap_unchecked().fun_id != fun_id
4547                            }
4548                        };
4549
4550                        pc = if should_jump {
4551                            pc.offset(i32::from(instruction.d()) as isize)
4552                        } else {
4553                            pc.add(1)
4554                        };
4555                        proto.assert_vm_pc(pc);
4556                    }
4557                }
4558
4559                break 'dispatch;
4560            }
4561        }
4562    }
4563}