Skip to main content

luaur_code_gen/functions/
execute_forgprep.rs

1//! Node: `cxx:Function:Luau.CodeGen:CodeGen/src/CodeGenUtils.cpp:762:execute_forgprep`
2//! Source: `CodeGen/src/CodeGenUtils.cpp`
3//! Graph edges:
4//! - declared_by: source_file CodeGen/src/CodeGenUtils.cpp
5//! - source_includes:
6//!   - includes -> source_file CodeGen/src/CodeGenUtils.h
7//!   - includes -> source_file VM/src/lvm.h
8//!   - includes -> source_file VM/src/lbuiltins.h
9//!   - includes -> source_file VM/src/lbytecode.h
10//!   - includes -> source_file VM/src/ldebug.h
11//!   - includes -> source_file VM/src/ldo.h
12//!   - includes -> source_file VM/src/lfunc.h
13//!   - includes -> source_file VM/src/lgc.h
14//!   - includes -> source_file VM/src/lmem.h
15//!   - includes -> source_file VM/src/lnumutils.h
16//!   - includes -> source_file VM/src/lstate.h
17//!   - includes -> source_file VM/src/lstring.h
18//!   - includes -> source_file VM/src/ltable.h
19//!   - includes -> source_file VM/src/ludata.h
20//! - incoming:
21//!   - declares <- source_file CodeGen/src/CodeGenUtils.cpp
22//! - outgoing:
23//!   - type_ref -> type_alias lua_State (CodeGen/include/luacodegen.h)
24//!   - type_ref -> type_alias StkId (VM/src/lobject.h)
25//!   - type_ref -> type_alias TValue (VM/src/lobject.h)
26//!   - calls -> macro clvalue (VM/src/lobject.h)
27//!   - calls -> macro VM_REG (CodeGen/src/CodeGenUtils.cpp)
28//!   - reads_global -> macro VM_REG (CodeGen/src/CodeGenUtils.cpp)
29//!   - calls -> macro LUAU_INSN_A (Common/include/Luau/Bytecode.h)
30//!   - reads_global -> macro LUAU_INSN_A (Common/include/Luau/Bytecode.h)
31//!   - calls -> macro ttisfunction (VM/src/lobject.h)
32//!   - calls -> macro ttistable (VM/src/lobject.h)
33//!   - calls -> macro hvalue (VM/src/lobject.h)
34//!   - calls -> macro ttisuserdata (VM/src/lobject.h)
35//!   - calls -> macro uvalue (VM/src/lobject.h)
36//!   - calls -> macro cast_to (VM/src/lcommon.h)
37//!   - calls -> macro fasttm (VM/src/ltm.h)
38//!   - calls -> macro setobj2s (VM/src/lobject.h)
39//!   - calls -> macro LUAU_ASSERT (Common/include/Luau/Common.h)
40//!   - reads_global -> macro LUAU_ASSERT (Common/include/Luau/Common.h)
41//!   - calls -> macro VM_PROTECT (CodeGen/src/CodeGenUtils.cpp)
42//!   - reads_global -> macro VM_PROTECT (CodeGen/src/CodeGenUtils.cpp)
43//!   - calls -> function luaD_call (VM/src/ldo.cpp)
44//!   - calls -> macro ttisnil (VM/src/lobject.h)
45//!   - calls -> macro VM_PROTECT_PC (CodeGen/src/CodeGenUtils.cpp)
46//!   - reads_global -> macro VM_PROTECT_PC (CodeGen/src/CodeGenUtils.cpp)
47//!   - calls -> macro luaG_typeerror (VM/src/ldebug.h)
48//!   - calls -> macro setpvalue (VM/src/lobject.h)
49//!   - reads_global -> macro LU_TAG_ITERATOR (VM/src/lobject.h)
50//!   - calls -> macro setnilvalue (VM/src/lobject.h)
51//!   - calls -> macro LUAU_INSN_D (Common/include/Luau/Bytecode.h)
52//!   - reads_global -> macro LUAU_INSN_D (Common/include/Luau/Bytecode.h)
53//!   - translates_to -> rust_item executeFORGPREP
54
55use luaur_vm::macros::clvalue::clvalue;
56use luaur_vm::macros::fasttm::fasttm;
57use luaur_vm::macros::hvalue::hvalue;
58use luaur_vm::macros::lu_tag_iterator::LU_TAG_ITERATOR;
59use luaur_vm::macros::setnilvalue::setnilvalue;
60use luaur_vm::macros::setobj_2_s::setobj2s;
61use luaur_vm::macros::setpvalue::setpvalue;
62use luaur_vm::macros::ttisfunction::ttisfunction;
63use luaur_vm::macros::ttisnil::ttisnil;
64use luaur_vm::macros::ttistable::ttistable;
65use luaur_vm::macros::ttisuserdata::ttisuserdata;
66use luaur_vm::macros::uvalue::uvalue;
67use luaur_vm::records::lua_table::LuaTable;
68use luaur_vm::type_aliases::stk_id::StkId;
69use luaur_vm::type_aliases::t_value::TValue;
70use luaur_vm::type_aliases::tms::TMS;
71
72use crate::macros::vm_protect::vm_protect;
73use crate::macros::vm_protect_pc::VM_PROTECT_PC;
74use crate::macros::vm_reg::VM_REG;
75use crate::type_aliases::instruction_ir_builder::Instruction;
76use crate::type_aliases::lua_state::lua_State;
77
78use luaur_common::macros::luau_insn_a::LUAU_INSN_A;
79use luaur_common::macros::luau_insn_d::LUAU_INSN_D;
80
81pub unsafe fn execute_forgprep(
82    L: *mut lua_State,
83    pc: *const Instruction,
84    mut base: StkId,
85    _k: *mut TValue,
86) -> *const Instruction {
87    let _cl = clvalue!((*(*L).ci).func);
88
89    let mut pc = pc;
90    let insn = *pc;
91    pc = pc.add(1);
92
93    let mut ra = VM_REG!(LUAU_INSN_A!(insn) as i32, L, base) as *mut TValue;
94
95    if ttisfunction!(ra) {
96        // will be called during FORGLOOP
97    } else {
98        let mt: *mut LuaTable = if ttistable!(ra) {
99            (*hvalue!(ra)).metatable
100        } else if ttisuserdata!(ra) {
101            (*uvalue!(ra as *const TValue)).metatable
102        } else {
103            core::ptr::null_mut()
104        };
105
106        let fn_iter = fasttm(L, mt, TMS::TM_ITER as i32);
107
108        if !fn_iter.is_null() {
109            setobj2s!(L, ra.add(1), ra);
110            setobj2s!(L, ra, fn_iter);
111
112            (*L).top = ra.add(2); // func + self arg
113
114            vm_protect!(L, pc, base, lua_d_call_protected(L, ra));
115            (*L).top = (*(*L).ci).top;
116
117            // recompute ra since stack might have been reallocated
118            ra = VM_REG!(LUAU_INSN_A!(insn) as i32, L, base) as *mut TValue;
119
120            // protect against __iter returning nil
121            if ttisnil!(ra) {
122                VM_PROTECT_PC(L, pc as *const u32);
123                luaur_vm::functions::lua_g_typeerror_l::lua_g_typeerror_l(
124                    L,
125                    ra as *const TValue,
126                    c"call".as_ptr(),
127                );
128            }
129        } else if !fasttm(L, mt, TMS::TM_CALL as i32).is_null() {
130            // table or userdata with __call, will be called during FORGLOOP
131        } else if ttistable!(ra) {
132            // set up registers for builtin iteration
133            setobj2s!(L, ra.add(1), ra);
134            setpvalue!(ra.add(2), core::ptr::null_mut(), LU_TAG_ITERATOR);
135            setnilvalue!(ra);
136        } else {
137            VM_PROTECT_PC(L, pc as *const u32);
138            luaur_vm::functions::lua_g_typeerror_l::lua_g_typeerror_l(
139                L,
140                ra as *const TValue,
141                c"iterate over".as_ptr(),
142            );
143        }
144    }
145
146    pc = pc.offset(LUAU_INSN_D!(insn) as isize);
147    pc
148}
149
150#[inline]
151unsafe fn lua_d_call_protected(L: *mut lua_State, ra: StkId) {
152    luaur_vm::functions::lua_d_call::lua_d_call(L, ra, 3);
153}
154
155#[no_mangle]
156pub unsafe extern "C" fn executeFORGPREP(
157    L: *mut lua_State,
158    pc: *const Instruction,
159    base: StkId,
160    k: *mut TValue,
161) -> *const Instruction {
162    execute_forgprep(L, pc, base, k)
163}