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() {
if (state.stack_size) {
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();
}
state.stack_size = 0;
@ -300,8 +301,6 @@ GDScriptFunctionState::GDScriptFunctionState() :
}
GDScriptFunctionState::~GDScriptFunctionState() {
_clear_stack();
{
MutexLock lock(GDScriptLanguage::singleton->lock);
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[ADDR_STACK_NIL], Variant);
if (_instruction_args_size) {
instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else {
instruction_args = nullptr;
}
if (p_instance) {
memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
script = p_instance->script.ptr();
} else {
memnew_placement(&stack[ADDR_STACK_SELF], Variant);
script = _script;
for (const KeyValue<int, Variant::Type> &E : temporary_slots) {
type_init_function_table[E.value](&stack[E.key]);
}
}
if (_ptrcall_args_size) {
call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *));
} else {
call_args_ptr = nullptr;
}
memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
for (const KeyValue<int, Variant::Type> &E : temporary_slots) {
type_init_function_table[E.value](&stack[E.key]);
if (p_instance) {
memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
script = p_instance->script.ptr();
} 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;
@ -2171,8 +2170,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
// Is this even possible to be null at this point?
if (obj) {
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->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]));
}
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;
}
// Check if this is the last time the function is resuming from await
// Will be true if never awaited as well
// When it's the last resume it will postpone the exit from stack,
// so the debugger knows which function triggered the resume of the next function (if any)
if (!p_state || awaited) {
// Check if this function has been interrupted by `await`.
// If that is the case we want to keep it in the debugger until it actually exits.
// This ensures the call stack can be properly shown when using `await`, showing what resumed the function.
if (!awaited) {
if (EngineDebugger::is_active()) {
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
// 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;
}