Skip to content

Commit f4fba79

Browse files
committed
update
1 parent b5bba3a commit f4fba79

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

crates/luars/src/gc/mod.rs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,20 +1134,36 @@ impl GC {
11341134
/// Uses a worklist algorithm to avoid recursion and handle borrowing correctly
11351135
fn mark_roots(&self, roots: &[LuaValue], pool: &mut ObjectPool) {
11361136
let mut worklist: Vec<LuaValue> = roots.to_vec();
1137+
// Track which fixed tables we've already traversed (to avoid infinite loops)
1138+
let mut traversed_fixed: std::collections::HashSet<u32> = std::collections::HashSet::new();
11371139

11381140
while let Some(value) = worklist.pop() {
11391141
match value.kind() {
11401142
crate::lua_value::LuaValueKind::Table => {
11411143
if let Some(id) = value.as_table_id() {
11421144
if let Some(table) = pool.tables.get_mut(id.0) {
1143-
if table.header.is_white() {
1144-
table.header.make_black();
1145+
// For fixed tables: traverse if not yet traversed
1146+
// For non-fixed tables: traverse if white (not yet marked)
1147+
let is_fixed = table.header.is_fixed();
1148+
let should_traverse = if is_fixed {
1149+
traversed_fixed.insert(id.0) // Returns true if newly inserted
1150+
} else {
1151+
table.header.is_white()
1152+
};
1153+
1154+
if should_traverse {
1155+
// Mark non-fixed tables as black
1156+
if !is_fixed {
1157+
table.header.make_black();
1158+
}
11451159
// Add table contents to worklist
1146-
for (k, v) in table.data.iter_all() {
1160+
let entries = table.data.iter_all();
1161+
let mt = table.data.get_metatable();
1162+
for (k, v) in entries {
11471163
worklist.push(k);
11481164
worklist.push(v);
11491165
}
1150-
if let Some(mt) = table.data.get_metatable() {
1166+
if let Some(mt) = mt {
11511167
worklist.push(mt);
11521168
}
11531169
}

crates/luars/src/lua_vm/mod.rs

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use std::rc::Rc;
2121
pub type LuaResult<T> = Result<T, LuaError>;
2222

2323
/// Maximum call stack depth (similar to LUAI_MAXCCALLS in Lua)
24-
/// Lua uses 200 for the limit, we use 256 for power-of-2 alignment
25-
pub const MAX_CALL_DEPTH: usize = 256;
24+
/// Using a lower limit because Rust stack space is limited
25+
pub const MAX_CALL_DEPTH: usize = 64;
2626

2727
pub struct LuaVM {
2828
// Global environment table (_G and _ENV point to this)
@@ -403,12 +403,33 @@ impl LuaVM {
403403
// - Main VM: pre-filled to MAX_CALL_DEPTH for direct index access
404404
// - Coroutines: start small and grow on demand (like Lua's linked list CallInfo)
405405

406+
/// Push a new frame onto the call stack and return stable pointer
407+
/// OPTIMIZED: Direct index write when capacity allows, grow on demand otherwise
408+
/// Returns None if call stack overflow (for pcall error handling)
409+
#[inline(always)]
410+
pub(crate) fn try_push_frame(&mut self, frame: LuaCallFrame) -> Option<*mut LuaCallFrame> {
411+
let idx = self.frame_count;
412+
if idx >= MAX_CALL_DEPTH {
413+
return None; // Stack overflow
414+
}
415+
416+
// Fast path: direct write if Vec is pre-filled or has space
417+
if idx < self.frames.len() {
418+
self.frames[idx] = frame;
419+
} else {
420+
// Slow path: grow the Vec (for coroutines with on-demand allocation)
421+
self.frames.push(frame);
422+
}
423+
self.frame_count = idx + 1;
424+
Some(&mut self.frames[idx] as *mut LuaCallFrame)
425+
}
426+
406427
/// Push a new frame onto the call stack and return stable pointer
407428
/// OPTIMIZED: Direct index write when capacity allows, grow on demand otherwise
408429
#[inline(always)]
409430
pub(crate) fn push_frame(&mut self, frame: LuaCallFrame) -> *mut LuaCallFrame {
410431
let idx = self.frame_count;
411-
debug_assert!(idx < MAX_CALL_DEPTH, "call stack overflow");
432+
assert!(idx < MAX_CALL_DEPTH, "call stack overflow");
412433

413434
// Fast path: direct write if Vec is pre-filled or has space
414435
if idx < self.frames.len() {
@@ -2767,7 +2788,9 @@ impl LuaVM {
27672788
}
27682789

27692790
let temp_frame = LuaCallFrame::new_c_function(new_base, stack_size);
2770-
self.push_frame(temp_frame);
2791+
if self.try_push_frame(temp_frame).is_none() {
2792+
return Err(self.error("C stack overflow".to_string()));
2793+
}
27712794

27722795
match cfunc(self) {
27732796
Ok(r) => {
@@ -2823,9 +2846,11 @@ impl LuaVM {
28232846
}
28242847
}
28252848

2826-
// Push boundary frame and Lua function frame
2849+
// Push boundary frame and Lua function frame - check for stack overflow
28272850
let boundary_frame = LuaCallFrame::new_c_function(new_base, 0);
2828-
self.push_frame(boundary_frame);
2851+
if self.try_push_frame(boundary_frame).is_none() {
2852+
return Err(self.error("C stack overflow".to_string()));
2853+
}
28292854

28302855
let new_frame = LuaCallFrame::new_lua_function(
28312856
func_id,
@@ -2838,7 +2863,10 @@ impl LuaVM {
28382863
-1,
28392864
max_stack_size,
28402865
);
2841-
self.push_frame(new_frame);
2866+
if self.try_push_frame(new_frame).is_none() {
2867+
self.pop_frame_discard(); // Pop the boundary frame
2868+
return Err(self.error("C stack overflow".to_string()));
2869+
}
28422870

28432871
let exec_result = execute::luavm_execute(self);
28442872

@@ -2940,7 +2968,9 @@ impl LuaVM {
29402968

29412969
// Create C function frame
29422970
let temp_frame = LuaCallFrame::new_c_function(new_base, stack_size);
2943-
self.push_frame(temp_frame);
2971+
if self.try_push_frame(temp_frame).is_none() {
2972+
return Err(self.error("C stack overflow".to_string()));
2973+
}
29442974

29452975
// Call CFunction
29462976
let result = match cfunc(self) {
@@ -3006,7 +3036,9 @@ impl LuaVM {
30063036

30073037
// Push C function boundary frame - RETURN will detect this and write to return_values
30083038
let boundary_frame = LuaCallFrame::new_c_function(new_base, 0);
3009-
self.push_frame(boundary_frame);
3039+
if self.try_push_frame(boundary_frame).is_none() {
3040+
return Err(self.error("C stack overflow".to_string()));
3041+
}
30103042

30113043
// Push Lua function frame
30123044
let new_frame = LuaCallFrame::new_lua_function(
@@ -3020,7 +3052,10 @@ impl LuaVM {
30203052
-1, // LUA_MULTRET
30213053
max_stack_size,
30223054
);
3023-
self.push_frame(new_frame);
3055+
if self.try_push_frame(new_frame).is_none() {
3056+
self.pop_frame_discard(); // Pop the boundary frame
3057+
return Err(self.error("C stack overflow".to_string()));
3058+
}
30243059

30253060
// Execute using the main dispatcher - no duplicate code!
30263061
let exec_result = execute::luavm_execute(self);

0 commit comments

Comments
 (0)