@@ -252,9 +252,7 @@ impl LuaVM {
252252 /// Main execution loop - interprets bytecode instructions
253253 /// Main VM execution loop - MAXIMUM PERFORMANCE
254254 /// 零返回值,零分支,直接调度
255- fn run ( & mut self ) -> LuaResult < LuaValue > {
256- let mut instruction_count: u32 = 0 ;
257-
255+ fn run ( & mut self ) -> LuaResult < LuaValue > {
258256 loop {
259257 // 检查是否有帧
260258 if self . frames . is_empty ( ) {
@@ -265,27 +263,17 @@ impl LuaVM {
265263 . unwrap_or ( LuaValue :: nil ( ) ) ) ;
266264 }
267265
268- // 周期性 GC 检查 (每 10000 条指令)
269- instruction_count += 1 ;
270- if instruction_count % 10000 == 0 {
271- self . check_gc ( ) ;
272- }
273-
274- // === 极简主循环:直接调度,无返回值 ===
275266 let frame = unsafe { self . frames . last_mut ( ) . unwrap_unchecked ( ) } ;
276267 let instr = unsafe { * frame. code_ptr . add ( frame. pc ) } ;
277268 frame. pc += 1 ;
278269
279- // 直接调度 - 指令自己处理一切(包括 Skip1、Return 等)
270+
280271 if let Err ( e) = dispatch_instruction ( self , instr) {
281272 match e {
282273 LuaError :: Yield ( _) => return Ok ( LuaValue :: nil ( ) ) ,
283274 _ => return Err ( e) ,
284275 }
285276 }
286-
287- // 检查函数返回(通过 frames 是否改变来判断)
288- // 这个检查很便宜,因为大部分时候都不会返回
289277 }
290278 }
291279
@@ -1184,6 +1172,15 @@ impl LuaVM {
11841172 /// - Long string: 1 Box allocation, GC registration, no pooling
11851173 pub fn create_string ( & mut self , s : & str ) -> LuaValue {
11861174 let id = self . object_pool . create_string ( s) ;
1175+
1176+ // Estimate memory cost: string data + LuaString struct overhead
1177+ // LuaString: ~32 bytes base + string length
1178+ let estimated_bytes = 32 + s. len ( ) ;
1179+ self . gc . record_allocation ( estimated_bytes) ;
1180+
1181+ // GC check MUST NOT happen here - object not yet protected!
1182+ // Caller must call check_gc() AFTER storing value in register
1183+
11871184 // Get pointer from object pool for direct access
11881185 let ptr = self
11891186 . object_pool
@@ -1207,10 +1204,20 @@ impl LuaVM {
12071204 pub fn create_table ( & mut self , array_size : usize , hash_size : usize ) -> LuaValue {
12081205 let id = self . object_pool . create_table ( array_size, hash_size) ;
12091206
1207+ // Estimate memory cost: base overhead + array + hash part
1208+ // Base: ~64 bytes for LuaTable struct + Rc overhead
1209+ // Array: array_size * 16 bytes per LuaValue
1210+ // Hash: hash_size * 32 bytes per Node (key+value pair)
1211+ let estimated_bytes = 64 + ( array_size * 16 ) + ( hash_size * 32 ) ;
1212+ self . gc . record_allocation ( estimated_bytes) ;
1213+
12101214 // Register with GC for manual collection
12111215 self . gc
12121216 . register_object ( id. 0 , crate :: gc:: GcObjectType :: Table ) ;
12131217
1218+ // GC check MUST NOT happen here - object not yet protected!
1219+ // Caller must call check_gc() AFTER storing value in register
1220+
12141221 // Get pointer from object pool for direct access
12151222 // OPTIMIZATION: Use unwrap_unchecked in release mode since we just created the table
12161223 let ptr = unsafe {
@@ -1355,23 +1362,23 @@ impl LuaVM {
13551362 }
13561363 }
13571364
1358- /// Check if GC should run and collect garbage if needed
1359- #[ allow( unused) ]
1360- fn maybe_collect_garbage ( & mut self ) {
1361- if self . gc . should_collect ( ) {
1362- self . collect_garbage ( ) ;
1363- }
1364- }
1365-
13661365 /// Check GC and run a step if needed (like luaC_checkGC in Lua 5.4)
1367- /// This should be called after allocating new objects
1368- /// CURRENTLY DISABLED: Needs better object lifetime management
1369- #[ inline]
1366+ /// This is called after allocating new objects (strings, tables, functions)
1367+ /// Uses GC debt mechanism: runs when debt > 0
1368+ ///
1369+ /// OPTIMIZATION: Use incremental collection with work budget
13701370 fn check_gc ( & mut self ) {
1371+ // Fast path: check debt without collecting roots
13711372 if !self . gc . should_collect ( ) {
13721373 return ;
13731374 }
13741375
1376+ // Incremental GC: only collect every N checks to reduce overhead
1377+ self . gc . increment_check_counter ( ) ;
1378+ if !self . gc . should_run_collection ( ) {
1379+ return ;
1380+ }
1381+
13751382 // Collect roots: all reachable objects from VM state
13761383 let mut roots = Vec :: new ( ) ;
13771384
0 commit comments