luaur_vm/functions/
lua_gc.rs1use crate::enums::lua_gc_op::lua_GCOp;
2use crate::functions::lua_c_fullgc::lua_c_fullgc;
3use crate::functions::lua_c_step::luaC_step;
4use crate::functions::lua_c_validate::lua_c_validate;
5use crate::macros::cast_int::cast_int;
6use crate::macros::condhardmemtests::condhardmemtests;
7use crate::records::gc_cycle_metrics::GCCycleMetrics;
8use crate::records::global_state::global_State;
9use crate::type_aliases::lua_state::lua_State;
10use luaur_common::macros::luau_assert::LUAU_ASSERT;
11
12pub const GCSpause: core::ffi::c_int = 0;
13pub const GCSpropagate: core::ffi::c_int = 1;
14pub const GCSpropagateagain: core::ffi::c_int = 2;
15pub const GCSatomic: core::ffi::c_int = 3;
16pub const GCSsweep: core::ffi::c_int = 4;
17
18#[allow(non_snake_case)]
19pub fn lua_gc(
20 L: *mut lua_State,
21 what: core::ffi::c_int,
22 data: core::ffi::c_int,
23) -> core::ffi::c_int {
24 let mut res: core::ffi::c_int = 0;
25 unsafe {
26 condhardmemtests!(lua_c_validate(L), 1);
27 let g: *mut global_State = (*L).global;
28 match what as i32 {
29 x if x == lua_GCOp::LUA_GCSTOP as i32 => {
30 (*g).GCthreshold = usize::MAX;
31 }
32 x if x == lua_GCOp::LUA_GCRESTART as i32 => {
33 (*g).GCthreshold = (*g).totalbytes;
34 }
35 x if x == lua_GCOp::LUA_GCCOLLECT as i32 => {
36 lua_c_fullgc(L);
37 }
38 x if x == lua_GCOp::LUA_GCCOUNT as i32 => {
39 res = cast_int!((*g).totalbytes >> 10);
40 }
41 x if x == lua_GCOp::LUA_GCCOUNTB as i32 => {
42 res = cast_int!((*g).totalbytes & 1023);
43 }
44 x if x == lua_GCOp::LUA_GCISRUNNING as i32 => {
45 res = if (*g).GCthreshold != usize::MAX { 1 } else { 0 };
46 }
47 x if x == lua_GCOp::LUA_GCSTEP as i32 => {
48 let amount: usize = (data as usize) << 10;
49 let gcstate_i32: i32 = i32::from((*g).gcstate);
50
51 let oldcredit: ptrdiff_t = if gcstate_i32 == GCSpause {
52 0
53 } else {
54 (*g).GCthreshold as ptrdiff_t - (*g).totalbytes as ptrdiff_t
55 };
56
57 if amount <= (*g).totalbytes {
59 (*g).GCthreshold = (*g).totalbytes - amount;
60 } else {
61 (*g).GCthreshold = 0;
62 }
63
64 #[cfg(feature = "luai_gcmetrics")]
65 let startmarktime = (*g).gcmetrics.currcycle.marktime;
66 #[cfg(feature = "luai_gcmetrics")]
67 let startsweeptime = (*g).gcmetrics.currcycle.sweeptime;
68
69 let mut actualwork: usize = 0;
71
72 while (*g).GCthreshold <= (*g).totalbytes {
73 let stepsize = luaC_step(L, false);
74 actualwork += stepsize;
75
76 let gcstate_i32 = i32::from((*g).gcstate);
77 if gcstate_i32 == GCSpause {
78 res = 1; break;
80 }
81 }
82
83 #[cfg(feature = "luai_gcmetrics")]
84 {
85 let cyclemetrics: &mut GCCycleMetrics = if i32::from((*g).gcstate) == GCSpause {
87 &mut (*g).gcmetrics.lastcycle
88 } else {
89 &mut (*g).gcmetrics.currcycle
90 };
91
92 let totalmarktime = cyclemetrics.marktime - startmarktime;
93 let totalsweeptime = cyclemetrics.sweeptime - startsweeptime;
94
95 if totalmarktime > 0.0 {
96 cyclemetrics.markexplicitsteps += 1;
97
98 if totalmarktime > cyclemetrics.markmaxexplicittime {
99 cyclemetrics.markmaxexplicittime = totalmarktime;
100 }
101 }
102
103 if totalsweeptime > 0.0 {
104 cyclemetrics.sweepexplicitsteps += 1;
105
106 if totalsweeptime > cyclemetrics.sweepmaxexplicittime {
107 cyclemetrics.sweepmaxexplicittime = totalsweeptime;
108 }
109 }
110 }
111
112 let gcstate_i32 = i32::from((*g).gcstate);
114 if gcstate_i32 != GCSpause {
115 let newthreshold =
117 (*g).totalbytes as ptrdiff_t + actualwork as ptrdiff_t + oldcredit;
118 (*g).GCthreshold = if newthreshold < 0 {
119 0
120 } else {
121 newthreshold as usize
122 };
123 }
124 }
125 x if x == lua_GCOp::LUA_GCSETGOAL as i32 => {
126 res = (*g).gcgoal;
127 (*g).gcgoal = data;
128 }
129 x if x == lua_GCOp::LUA_GCSETSTEPMUL as i32 => {
130 res = (*g).gcstepmul;
131 (*g).gcstepmul = data;
132 }
133 x if x == lua_GCOp::LUA_GCSETSTEPSIZE as i32 => {
134 res = (*g).gcstepsize >> 10;
136 (*g).gcstepsize = data << 10;
137 }
138 _ => {
139 res = -1; }
141 }
142 }
143 res
144}
145
146type ptrdiff_t = core::ffi::c_long;