Merge pull request #61003 from vnen/gdscript-await-stack-fix
This commit is contained in:
commit
c41f62c3df
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue