luaur-code-gen 0.1.3

Native (A64/X64) code generation for Luau (Rust).
Documentation
use crate::macros::vm_patch_c::VM_PATCH_C;
use crate::macros::vm_protect::vm_protect;
use crate::macros::vm_reg::VM_REG;
use crate::type_aliases::instruction_ir_builder::Instruction;
use crate::type_aliases::lua_state::lua_State;
use luaur_common::enums::luau_opcode::LuauOpcode;
use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
use luaur_common::macros::luau_insn_aux_kv_16::LUAU_INSN_AUX_KV16;
use luaur_common::macros::luau_insn_b::LUAU_INSN_B;
use luaur_common::macros::luau_insn_c::LUAU_INSN_C;
use luaur_common::macros::luau_insn_op::LUAU_INSN_OP;
use luaur_vm::functions::lua_g_methoderror::luaG_methoderror;
use luaur_vm::functions::lua_v_gettable::lua_v_gettable;
use luaur_vm::macros::clvalue::clvalue;
use luaur_vm::macros::fasttm::fasttm;
use luaur_vm::macros::gkey::{gkey, gval};
use luaur_vm::macros::hvalue::hvalue;
use luaur_vm::macros::setobj_2_s::setobj_2_s as setobj2s;
use luaur_vm::macros::tsvalue::tsvalue;
use luaur_vm::macros::ttisnil::ttisnil;
use luaur_vm::macros::ttisstring::ttisstring;
use luaur_vm::macros::ttistable::ttistable;
use luaur_vm::macros::ttisuserdata::ttisuserdata;
use luaur_vm::macros::ttype::ttype;
use luaur_vm::macros::uvalue::uvalue;
use luaur_vm::type_aliases::stk_id::StkId;
use luaur_vm::type_aliases::t_value::TValue;
use luaur_vm::type_aliases::tms::TMS;

#[inline]
unsafe fn vm_kv(
    i: u32,
    cl: *mut luaur_vm::records::closure::Closure,
    k: *mut TValue,
) -> *mut TValue {
    let p = {
        let l = &(*cl).inner.l;
        l.p
    };
    luaur_common::LUAU_ASSERT!(i < (*p).sizek as u32);
    k.add(i as usize)
}

pub unsafe fn execute_namecall(
    L: *mut lua_State,
    pc: *const Instruction,
    mut base: StkId,
    k: *mut TValue,
) -> *const Instruction {
    let cl = clvalue!((*(*L).ci).func);
    let mut pc_ptr = pc;
    let insn = *pc_ptr;
    pc_ptr = pc_ptr.add(1);
    let op = LUAU_INSN_OP(insn);
    let mut ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
    let rb = VM_REG!(LUAU_INSN_B(insn) as i32, L, base) as *mut TValue;
    let aux = *pc_ptr;
    pc_ptr = pc_ptr.add(1);
    let kv = vm_kv(
        if op == LuauOpcode::LOP_NAMECALLUDATA as u32 {
            LUAU_INSN_AUX_KV16(aux)
        } else {
            aux
        },
        cl,
        k,
    );
    luaur_common::LUAU_ASSERT!(ttisstring!(kv as *const TValue));

    if ttistable!(rb as *const TValue) {
        setobj2s!(L, ra.add(1), rb as *const TValue);
        (*L).cachedslot = LUAU_INSN_C(insn) as i32;
        vm_protect!(L, pc_ptr, base, {
            lua_v_gettable(L, rb as *const TValue, kv, ra);
        });
        VM_PATCH_C(pc_ptr.sub(2), (*L).cachedslot);

        ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
        if ttisnil!(ra as *const TValue) {
            luaG_methoderror(L, ra.add(1) as *const TValue, tsvalue!(kv as *const TValue));
        }
    } else {
        let mt = if ttisuserdata!(rb as *const TValue) {
            (*uvalue!(rb as *const TValue)).metatable
        } else {
            (*(*L).global).mt[ttype!(rb as *const TValue) as usize]
        };

        let fn_nc = fasttm(L, mt, TMS::TM_NAMECALL as i32);
        if !fn_nc.is_null() {
            setobj2s!(L, ra.add(1), rb as *const TValue);
            setobj2s!(L, ra, fn_nc);

            (*L).namecall = tsvalue!(kv as *const TValue) as *mut _;
        } else {
            let tmi = fasttm(L, mt, TMS::TM_INDEX as i32);
            if !tmi.is_null() && ttistable!(tmi) {
                let h = hvalue!(tmi);
                let slot = (LUAU_INSN_C(insn) as i32) & (*h).nodemask8 as i32;
                let n = (*h).node.add(slot as usize);

                if ttisstring!(gkey!(n) as *const TValue)
                    && tsvalue!(gkey!(n) as *const TValue) == tsvalue!(kv as *const TValue)
                    && !ttisnil!(gval!(n))
                {
                    setobj2s!(L, ra.add(1), rb as *const TValue);
                    setobj2s!(L, ra, gval!(n));
                } else {
                    setobj2s!(L, ra.add(1), rb as *const TValue);
                    (*L).cachedslot = slot;
                    vm_protect!(L, pc_ptr, base, {
                        lua_v_gettable(L, rb as *const TValue, kv, ra);
                    });
                    VM_PATCH_C(pc_ptr.sub(2), (*L).cachedslot);

                    ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
                    if ttisnil!(ra as *const TValue) {
                        luaG_methoderror(
                            L,
                            ra.add(1) as *const TValue,
                            tsvalue!(kv as *const TValue),
                        );
                    }
                }
            } else {
                setobj2s!(L, ra.add(1), rb as *const TValue);
                vm_protect!(L, pc_ptr, base, {
                    lua_v_gettable(L, rb as *const TValue, kv, ra);
                });

                ra = VM_REG!(LUAU_INSN_A(insn) as i32, L, base) as *mut TValue;
                if ttisnil!(ra as *const TValue) {
                    luaG_methoderror(L, ra.add(1) as *const TValue, tsvalue!(kv as *const TValue));
                }
            }
        }
    }

    luaur_common::LUAU_ASSERT!(
        LUAU_INSN_OP(*pc_ptr) == LuauOpcode::LOP_CALL as u32
            || LUAU_INSN_OP(*pc_ptr) == LuauOpcode::LOP_CALLFB as u32
    );
    pc_ptr
}

#[no_mangle]
pub unsafe extern "C" fn executeNAMECALL(
    L: *mut lua_State,
    pc: *const Instruction,
    base: StkId,
    k: *mut TValue,
) -> *const Instruction {
    execute_namecall(L, pc, base, k)
}