@@ -1228,31 +1228,34 @@ pub fn exec_return1(vm: &mut LuaVM, instr: u32, frame_ptr: *mut LuaCallFrame) ->
12281228 vm. close_upvalues_from ( base_ptr) ;
12291229 }
12301230
1231+ // Get return value before popping frame
1232+ let return_value = if base_ptr + a < vm. register_stack . len ( ) {
1233+ unsafe { * vm. register_stack . get_unchecked ( base_ptr + a) }
1234+ } else {
1235+ LuaValue :: nil ( )
1236+ } ;
1237+
12311238 // Pop frame - we already have all info we need from frame_ptr
12321239 unsafe { vm. frames . pop ( ) . unwrap_unchecked ( ) } ;
12331240
1234- // ULTRA-FAST PATH: Most calls have a caller, check length directly
1235- if vm. frames . len ( ) > 0 {
1236- // Get return value directly - no bounds check needed
1237- let return_value = unsafe { * vm. register_stack . get_unchecked ( base_ptr + a) } ;
1238-
1239- // Get caller frame directly
1240- let caller_frame = unsafe { vm. frames . last_mut ( ) . unwrap_unchecked ( ) } ;
1241-
1242- // Write to caller's result register - no bounds check needed
1241+ // CRITICAL: Always set return_values for call_function_internal compatibility
1242+ vm. return_values . clear ( ) ;
1243+ vm. return_values . push ( return_value) ;
1244+
1245+ // Check if there's a caller frame
1246+ if let Some ( caller_frame) = vm. frames . last_mut ( ) {
1247+ // Write to caller's result register
12431248 let dest_pos = caller_frame. base_ptr + result_reg;
1244- unsafe { * vm. register_stack . get_unchecked_mut ( dest_pos) = return_value; }
1249+ if dest_pos < vm. register_stack . len ( ) {
1250+ vm. register_stack [ dest_pos] = return_value;
1251+ }
12451252
12461253 // Update top
12471254 caller_frame. top = result_reg + 1 ;
12481255
12491256 Ok ( ( ) )
12501257 } else {
12511258 // No caller - exit VM (only happens at script end)
1252- vm. return_values . clear ( ) ;
1253- if base_ptr + a < vm. register_stack . len ( ) {
1254- vm. return_values . push ( vm. register_stack [ base_ptr + a] ) ;
1255- }
12561259 Err ( LuaError :: Exit )
12571260 }
12581261}
0 commit comments