Merge pull request #61003 from vnen/gdscript-await-stack-fix

This commit is contained in:
Rémi Verschelde 2022-05-16 14:10:29 +02:00 committed by GitHub
commit c41f62c3df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 34 deletions

View File

@ -279,7 +279,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
void GDScriptFunctionState::_clear_stack() { void GDScriptFunctionState::_clear_stack() {
if (state.stack_size) { if (state.stack_size) {
Variant *stack = (Variant *)state.stack.ptr(); Variant *stack = (Variant *)state.stack.ptr();
for (int i = 0; i < state.stack_size; i++) { // The first 3 are special addresses and not copied to the state, so we skip them here.
for (int i = 3; i < state.stack_size; i++) {
stack[i].~Variant(); stack[i].~Variant();
} }
state.stack_size = 0; state.stack_size = 0;
@ -300,8 +301,6 @@ GDScriptFunctionState::GDScriptFunctionState() :
} }
GDScriptFunctionState::~GDScriptFunctionState() { GDScriptFunctionState::~GDScriptFunctionState() {
_clear_stack();
{ {
MutexLock lock(GDScriptLanguage::singleton->lock); MutexLock lock(GDScriptLanguage::singleton->lock);
scripts_list.remove_from_list(); scripts_list.remove_from_list();

View File

@ -546,33 +546,32 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&stack[i], Variant); memnew_placement(&stack[i], Variant);
} }
memnew_placement(&stack[ADDR_STACK_NIL], Variant);
if (_instruction_args_size) { if (_instruction_args_size) {
instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size]; instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else { } else {
instruction_args = nullptr; instruction_args = nullptr;
} }
if (p_instance) { for (const KeyValue<int, Variant::Type> &E : temporary_slots) {
memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner)); type_init_function_table[E.value](&stack[E.key]);
script = p_instance->script.ptr();
} else {
memnew_placement(&stack[ADDR_STACK_SELF], Variant);
script = _script;
} }
} }
if (_ptrcall_args_size) { if (_ptrcall_args_size) {
call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *)); call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *));
} else { } else {
call_args_ptr = nullptr; call_args_ptr = nullptr;
} }
memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script)); if (p_instance) {
memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
for (const KeyValue<int, Variant::Type> &E : temporary_slots) { script = p_instance->script.ptr();
type_init_function_table[E.value](&stack[E.key]); } else {
memnew_placement(&stack[ADDR_STACK_SELF], Variant);
script = _script;
} }
memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
memnew_placement(&stack[ADDR_STACK_NIL], Variant);
String err_text; String err_text;
@ -2171,8 +2170,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
// Is this even possible to be null at this point? // Is this even possible to be null at this point?
if (obj) { if (obj) {
if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) { if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
static StringName completed = _scs_create("completed"); result = Signal(obj, "completed");
result = Signal(obj, completed);
} }
} }
} }
@ -2193,8 +2191,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
gdfs->function = this; gdfs->function = this;
gdfs->state.stack.resize(alloca_size); gdfs->state.stack.resize(alloca_size);
//copy variant stack
for (int i = 0; i < _stack_size; i++) { // First 3 stack addresses are special, so we just skip them here.
for (int i = 3; i < _stack_size; i++) {
memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i])); memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
} }
gdfs->state.stack_size = _stack_size; gdfs->state.stack_size = _stack_size;
@ -3451,26 +3450,24 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time; GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
} }
// Check if this is the last time the function is resuming from await // Check if this function has been interrupted by `await`.
// Will be true if never awaited as well // If that is the case we want to keep it in the debugger until it actually exits.
// When it's the last resume it will postpone the exit from stack, // This ensures the call stack can be properly shown when using `await`, showing what resumed the function.
// so the debugger knows which function triggered the resume of the next function (if any) if (!awaited) {
if (!p_state || awaited) {
if (EngineDebugger::is_active()) { if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->exit_function(); GDScriptLanguage::get_singleton()->exit_function();
} }
#endif
if (_stack_size) {
//free stack
for (int i = 0; i < _stack_size; i++) {
stack[i].~Variant();
}
}
#ifdef DEBUG_ENABLED
} }
#endif #endif
// Clear the stack even if there was an `await`.
// The stack saved in the state is a copy, so this needs to be destructed to avoid leaks.
if (_stack_size) {
// Free stack.
for (int i = 0; i < _stack_size; i++) {
stack[i].~Variant();
}
}
return retvalue; return retvalue;
} }