From e4034355de59af356104847ed8e6f6da95d05524 Mon Sep 17 00:00:00 2001 From: Danil Alexeev Date: Mon, 25 May 2026 23:06:45 +0300 Subject: [PATCH] GDScript: Move stack cleanup after resumed coroutine completion --- modules/gdscript/gdscript_vm.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index b470b15872..601989768b 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -4009,13 +4009,19 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } #endif - // Check if this is not the last time it was interrupted by `await` or if it's the first time executing. - // If that is the case then we exit the function as normal. Otherwise we postpone it until the last `await` is completed. - // This ensures the call stack can be properly shown when using `await`, showing what resumed the function. - if (!p_state || awaited) { - GDScriptLanguage::get_singleton()->exit_function(); + if (p_state && !awaited) { + // This means we have finished executing a resumed function and it was not awaited again. + // Exit function only after executing the remaining function states to preserve async call stack. + // Postpone the function exiting and the call stack clearing until the last `await` is completed. + // This ensures the call stack can be properly shown when using `await`, showing what resumed the function. + + // Signal the next function-state to resume. + const Variant *args[1] = { &retvalue }; + p_state->completed.emit(args, 1); } + GDScriptLanguage::get_singleton()->exit_function(); + // We deliberately avoid calling the destructor for `ADDR_STACK_CLASS`, since we initialized it // without incrementing any reference count that it might have. stack[ADDR_STACK_SELF].~Variant(); @@ -4027,16 +4033,5 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a call_depth--; - if (p_state && !awaited) { - // This means we have finished executing a resumed function and it was not awaited again. - - // Signal the next function-state to resume. - const Variant *args[1] = { &retvalue }; - p_state->completed.emit(args, 1); - - // Exit function only after executing the remaining function states to preserve async call stack. - GDScriptLanguage::get_singleton()->exit_function(); - } - return retvalue; }