Skip to main content

luaur_code_gen/functions/
call_step_gc.rs

1use crate::enums::condition_x_64::ConditionX64;
2use crate::enums::size_x_64::SizeX64;
3use crate::functions::emit_update_base_emit_common_x_64::emit_update_base;
4use crate::records::assembly_builder_x_64::AssemblyBuilderX64;
5use crate::records::ir_call_wrapper_x_64::IrCallWrapperX64;
6use crate::records::ir_data::k_invalid_inst_idx;
7use crate::records::ir_op::IrOp;
8use crate::records::ir_reg_alloc_x_64::IrRegAllocX64;
9use crate::records::label::Label;
10use crate::records::native_context::NativeContext;
11use crate::records::operand_x_64::OperandX64;
12use crate::records::register_x_64::RegisterX64;
13use crate::records::scoped_reg_x_64::ScopedRegX64;
14use crate::records::scoped_spills::ScopedSpills;
15use luaur_vm::records::global_state::global_State;
16use luaur_vm::records::lua_state::lua_State;
17
18pub fn call_step_gc(regs: &mut IrRegAllocX64, build: &mut AssemblyBuilderX64) {
19    let mut skip = Label::default();
20
21    {
22        let mut tmp1 = ScopedRegX64 {
23            owner: core::ptr::null_mut(),
24            reg: RegisterX64::noreg,
25        };
26        tmp1.scoped_reg_x_64_ir_reg_alloc_x_64_size_x_64(regs, SizeX64::qword);
27
28        let mut tmp2 = ScopedRegX64 {
29            owner: core::ptr::null_mut(),
30            reg: RegisterX64::noreg,
31        };
32        tmp2.scoped_reg_x_64_ir_reg_alloc_x_64_size_x_64(regs, SizeX64::qword);
33
34        build.mov(
35            OperandX64::reg(tmp1.reg),
36            mem(
37                SizeX64::qword,
38                r_state(),
39                core::mem::offset_of!(lua_State, global) as i32,
40            ),
41        );
42        build.mov(
43            OperandX64::reg(tmp2.reg),
44            mem(
45                SizeX64::qword,
46                tmp1.reg,
47                core::mem::offset_of!(global_State, totalbytes) as i32,
48            ),
49        );
50        build.cmp(
51            OperandX64::reg(tmp2.reg),
52            mem(
53                SizeX64::qword,
54                tmp1.reg,
55                core::mem::offset_of!(global_State, GCthreshold) as i32,
56            ),
57        );
58        build.jcc(ConditionX64::Below, &mut skip);
59    }
60
61    {
62        let _spill_guard = {
63            let mut guard = ScopedSpills {
64                owner: regs as *mut _,
65                start_spill_id: 0,
66            };
67            guard.scoped_spills_scoped_spills_ir_reg_alloc_x_64(regs);
68            guard
69        };
70
71        let mut call_wrap = IrCallWrapperX64::ir_call_wrapper_x_64_ir_call_wrapper_x_64(
72            regs,
73            build,
74            k_invalid_inst_idx,
75        );
76        call_wrap.add_argument_size_x_64_operand_x_64_ir_op(
77            SizeX64::qword,
78            OperandX64::reg(r_state()),
79            IrOp::ir_op(),
80        );
81        call_wrap.add_argument_size_x_64_operand_x_64_ir_op(
82            SizeX64::dword,
83            OperandX64::imm(1),
84            IrOp::ir_op(),
85        );
86        call_wrap.call(&mem(
87            SizeX64::qword,
88            r_native_context(),
89            core::mem::offset_of!(NativeContext, luaC_step) as i32,
90        ));
91        emit_update_base(build);
92    }
93
94    build.set_label_label(&mut skip);
95}
96
97const fn reg(index: u8, size: SizeX64) -> RegisterX64 {
98    RegisterX64 {
99        bits: (index << RegisterX64::INDEX_SHIFT) | size as u8,
100    }
101}
102
103const fn r_state() -> RegisterX64 {
104    reg(15, SizeX64::qword)
105}
106
107const fn r_native_context() -> RegisterX64 {
108    reg(13, SizeX64::qword)
109}
110
111fn mem(size: SizeX64, base: RegisterX64, disp: i32) -> OperandX64 {
112    OperandX64::mem(size, RegisterX64::noreg, 1, base, disp)
113}