Skip to content

Commit b25e3aa

Browse files
committed
fix performance test
1 parent fd30d28 commit b25e3aa

File tree

3 files changed

+66
-15
lines changed

3 files changed

+66
-15
lines changed

crates/luars/src/lua_vm/execute/control_instructions.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,8 +1211,10 @@ pub fn exec_tailcall(
12111211
return Err(vm.error("not a c function".to_string()));
12121212
};
12131213

1214-
// Set up arguments in a temporary stack space
1215-
let call_base = vm.register_stack.len();
1214+
// CRITICAL FIX: Use current frame's base for C function call
1215+
// This avoids growing register_stack infinitely on repeated tail calls
1216+
// The current frame's stack space is being reused since this is a tail call
1217+
let call_base = base;
12161218
vm.ensure_stack_capacity(call_base + args_len + 1);
12171219

12181220
vm.register_stack[call_base] = func;

crates/luars/src/lua_vm/execute/loop_instructions.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -306,17 +306,19 @@ pub fn exec_tforcall(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -
306306
let code_ptr = func_ref.chunk.code.as_ptr();
307307
let constants_ptr = func_ref.chunk.constants.as_ptr();
308308

309-
let call_base = vm.register_stack.len();
309+
// CRITICAL FIX: Use proper call base relative to current frame
310+
// Arguments are already at base_ptr + a + 4 and base_ptr + a + 5 (state, control)
311+
// New frame base should be at base_ptr + a + 4 where we placed the first arg
312+
let call_base = base_ptr + a + 4;
310313
vm.ensure_stack_capacity(call_base + max_stack_size);
311314

312-
// Initialize registers
313-
for i in 0..max_stack_size {
315+
// Initialize registers beyond arguments
316+
for i in 2..max_stack_size {
314317
vm.register_stack[call_base + i] = LuaValue::nil();
315318
}
316319

317-
// Copy arguments
318-
vm.register_stack[call_base] = state;
319-
vm.register_stack[call_base + 1] = control;
320+
// Arguments are already in place (state at +0, control at +1)
321+
// No need to copy them again
320322

321323
// Create new frame with correct nresults type
322324
let nresults = (c + 1) as i16;
@@ -325,9 +327,9 @@ pub fn exec_tforcall(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) -
325327
code_ptr,
326328
constants_ptr,
327329
call_base,
328-
max_stack_size, // top = max_stack_size (we initialized this many registers)
329-
a + 3, // result goes to R[A+3]
330-
nresults, // expecting c+1 results
330+
2, // top = 2 (we have 2 arguments)
331+
a + 3, // result goes to R[A+3]
332+
nresults, // expecting c+1 results
331333
);
332334

333335
vm.push_frame(new_frame);

crates/luars/src/lua_vm/mod.rs

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,8 +1802,24 @@ impl LuaVM {
18021802
let code_ptr = func_ref.chunk.code.as_ptr();
18031803
let constants_ptr = func_ref.chunk.constants.as_ptr();
18041804

1805-
// Allocate registers in global stack
1806-
let new_base = self.register_stack.len();
1805+
// CRITICAL FIX: Calculate new base relative to current frame
1806+
// This prevents register_stack from growing indefinitely
1807+
let new_base = if self.frame_count > 0 {
1808+
let current_frame = &self.frames[self.frame_count - 1];
1809+
let caller_base = current_frame.base_ptr;
1810+
let caller_max_stack =
1811+
if let Some(caller_func_id) = current_frame.function_value.as_function_id() {
1812+
self.object_pool
1813+
.get_function(caller_func_id)
1814+
.map(|f| f.chunk.max_stack_size)
1815+
.unwrap_or(256)
1816+
} else {
1817+
256
1818+
};
1819+
caller_base + caller_max_stack
1820+
} else {
1821+
0
1822+
};
18071823
self.ensure_stack_capacity(new_base + max_stack_size);
18081824

18091825
// Copy arguments to new frame's registers
@@ -1841,7 +1857,24 @@ impl LuaVM {
18411857
let cf = metamethod.as_cfunction().unwrap();
18421858
// Create temporary frame for CFunction
18431859
let arg_count = args.len() + 1; // +1 for function itself
1844-
let new_base = self.register_stack.len();
1860+
1861+
// CRITICAL FIX: Calculate new base relative to current frame
1862+
let new_base = if self.frame_count > 0 {
1863+
let current_frame = &self.frames[self.frame_count - 1];
1864+
let caller_base = current_frame.base_ptr;
1865+
let caller_max_stack =
1866+
if let Some(caller_func_id) = current_frame.function_value.as_function_id() {
1867+
self.object_pool
1868+
.get_function(caller_func_id)
1869+
.map(|f| f.chunk.max_stack_size)
1870+
.unwrap_or(256)
1871+
} else {
1872+
256
1873+
};
1874+
caller_base + caller_max_stack
1875+
} else {
1876+
0
1877+
};
18451878
self.ensure_stack_capacity(new_base + arg_count);
18461879

18471880
self.register_stack[new_base] = LuaValue::cfunction(cf);
@@ -2196,15 +2229,29 @@ impl LuaVM {
21962229
// Normal return - pop boundary frame and get return values
21972230
self.pop_frame_discard();
21982231
let result = std::mem::take(&mut self.return_values);
2232+
2233+
// Clear the stack region used by this call to release references
2234+
// This prevents GC from scanning stale objects after dofile/pcall
2235+
for i in new_base..(new_base + max_stack_size) {
2236+
if i < self.register_stack.len() {
2237+
self.register_stack[i] = LuaValue::nil();
2238+
}
2239+
}
2240+
21992241
Ok(result)
22002242
}
22012243
Err(LuaError::Yield) => {
22022244
// Yield - frames stay for resume
22032245
Err(LuaError::Yield)
22042246
}
22052247
Err(e) => {
2206-
// Error - pop boundary frame
2248+
// Error - pop boundary frame and clear stack region
22072249
self.pop_frame_discard();
2250+
for i in new_base..(new_base + max_stack_size) {
2251+
if i < self.register_stack.len() {
2252+
self.register_stack[i] = LuaValue::nil();
2253+
}
2254+
}
22082255
Err(e)
22092256
}
22102257
}

0 commit comments

Comments
 (0)