diff options
Diffstat (limited to 'modules')
7 files changed, 139 insertions, 51 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index de94557b41..046158e24e 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -2569,6 +2569,8 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o result = get_operation_type(p_binary_op->variant_op, left_type, right_type, valid, p_binary_op); if (!valid) { push_error(vformat(R"(Invalid operands "%s" and "%s" for "%s" operator.)", left_type.to_string(), right_type.to_string(), Variant::get_operator_name(p_binary_op->variant_op)), p_binary_op); + } else if (result.type_source != GDScriptParser::DataType::ANNOTATED_EXPLICIT) { + mark_node_unsafe(p_binary_op); } } else { ERR_PRINT("Parser bug: unknown binary operation."); diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 73f88d2932..a13bf8009f 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -143,6 +143,11 @@ void GDScriptByteCodeGenerator::pop_temporary() { ERR_FAIL_COND(used_temporaries.is_empty()); int slot_idx = used_temporaries.back()->get(); const StackSlot &slot = temporaries[slot_idx]; + if (slot.type == Variant::OBJECT) { + // Avoid keeping in the stack long-lived references to objects, + // which may prevent RefCounted objects from being freed. + write_assign_false(Address(Address::TEMPORARY, slot_idx)); + } temporaries_pool[slot.type].push_back(slot_idx); used_temporaries.pop_back(); } @@ -980,7 +985,7 @@ void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Addres append(index); } -GDScriptCodeGenerator::Address GDScriptByteCodeGenerator::get_call_target(const GDScriptCodeGenerator::Address &p_target, Variant::Type p_type) { +GDScriptByteCodeGenerator::CallTarget GDScriptByteCodeGenerator::get_call_target(const GDScriptCodeGenerator::Address &p_target, Variant::Type p_type) { if (p_target.mode == Address::NIL) { GDScriptDataType type; if (p_type != Variant::NIL) { @@ -989,10 +994,9 @@ GDScriptCodeGenerator::Address GDScriptByteCodeGenerator::get_call_target(const type.builtin_type = p_type; } uint32_t addr = add_temporary(type); - pop_temporary(); - return Address(Address::TEMPORARY, addr, type); + return CallTarget(Address(Address::TEMPORARY, addr, type), true, this); } else { - return p_target; + return CallTarget(p_target, false, this); } } @@ -1002,9 +1006,11 @@ void GDScriptByteCodeGenerator::write_call(const Address &p_target, const Addres append(p_arguments[i]); } append(p_base); - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_function_name); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) { @@ -1012,9 +1018,11 @@ void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_function_name); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) { @@ -1023,9 +1031,11 @@ void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const append(p_arguments[i]); } append(p_base); - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_function_name); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) { @@ -1034,9 +1044,11 @@ void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_tar for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(gds_function); + ct.cleanup(); #ifdef DEBUG_ENABLED add_debug_name(gds_utilities_names, get_gds_utility_pos(gds_function), p_function); #endif @@ -1060,18 +1072,19 @@ void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, cons if (is_validated) { Variant::Type result_type = Variant::has_utility_function_return_value(p_function) ? Variant::get_utility_function_return_type(p_function) : Variant::NIL; - Address target = get_call_target(p_target, result_type); - Variant::Type temp_type = temporaries[target.address].type; + CallTarget ct = get_call_target(p_target, result_type); + Variant::Type temp_type = temporaries[ct.target.address].type; if (result_type != temp_type) { - write_type_adjust(target, result_type); + write_type_adjust(ct.target, result_type); } append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY_VALIDATED, 1 + p_arguments.size()); for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(target); + append(ct.target); append(p_arguments.size()); append(Variant::get_validated_utility_function(p_function)); + ct.cleanup(); #ifdef DEBUG_ENABLED add_debug_name(utilities_names, get_utility_pos(Variant::get_validated_utility_function(p_function)), p_function); #endif @@ -1080,9 +1093,11 @@ void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, cons for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_function); + ct.cleanup(); } } @@ -1111,10 +1126,12 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_type); append(p_method); append(p_arguments.size()); + ct.cleanup(); } else { write_call(p_target, p_base, p_method, p_arguments); } @@ -1122,10 +1139,10 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, } Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method); - Address target = get_call_target(p_target, result_type); - Variant::Type temp_type = temporaries[target.address].type; + CallTarget ct = get_call_target(p_target, result_type); + Variant::Type temp_type = temporaries[ct.target.address].type; if (result_type != temp_type) { - write_type_adjust(target, result_type); + write_type_adjust(ct.target, result_type); } append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size()); @@ -1134,9 +1151,11 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, append(p_arguments[i]); } append(p_base); - append(target); + append(ct.target); append(p_arguments.size()); append(Variant::get_validated_builtin_method(p_type, p_method)); + ct.cleanup(); + #ifdef DEBUG_ENABLED add_debug_name(builtin_methods_names, get_builtin_method_pos(Variant::get_validated_builtin_method(p_type, p_method)), p_method); #endif @@ -1161,9 +1180,11 @@ void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(method); append(p_arguments.size()); + ct.cleanup(); return; } } @@ -1173,10 +1194,12 @@ void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } + CallTarget ct = get_call_target(p_target); append(p_base); - append(get_call_target(p_target)); + append(ct.target); append(p_arguments.size()); append(p_method); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) { @@ -1238,9 +1261,11 @@ void GDScriptByteCodeGenerator::write_call_ptrcall(const Address &p_target, cons append(p_arguments[i]); } append(p_base); - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_method); + ct.cleanup(); if (is_ptrcall) { alloc_ptrcall(p_arguments.size()); } @@ -1254,9 +1279,11 @@ void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const S append(p_arguments[i]); } append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS); - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_function_name); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) { @@ -1265,9 +1292,11 @@ void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, c append(p_arguments[i]); } append(GDScriptFunction::ADDR_SELF); - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_function_name); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) { @@ -1276,9 +1305,11 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ append(p_arguments[i]); } append(p_base); - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_function_name); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) { @@ -1287,9 +1318,11 @@ void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFu append(p_captures[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_captures.size()); append(p_function); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) { @@ -1326,9 +1359,11 @@ void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(Variant::get_validated_constructor(p_type, valid_constructor)); + ct.cleanup(); #ifdef DEBUG_ENABLED add_debug_name(constructors_names, get_constructor_pos(Variant::get_validated_constructor(p_type, valid_constructor)), Variant::get_type_name(p_type)); #endif @@ -1340,9 +1375,11 @@ void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); append(p_type); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) { @@ -1350,8 +1387,10 @@ void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, c for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size()); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) { @@ -1359,11 +1398,13 @@ void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_tar for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(get_constant_pos(p_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); append(p_arguments.size()); append(p_element_type.builtin_type); append(p_element_type.native_type); + ct.cleanup(); } void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) { @@ -1371,8 +1412,10 @@ void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_targ for (int i = 0; i < p_arguments.size(); i++) { append(p_arguments[i]); } - append(get_call_target(p_target)); + CallTarget ct = get_call_target(p_target); + append(ct.target); append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments. + ct.cleanup(); } void GDScriptByteCodeGenerator::write_await(const Address &p_target, const Address &p_operand) { diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index 03f555a85d..dc05de9fc6 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -48,6 +48,33 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { const static int RESERVED_STACK = 3; // For self, class, and nil. + struct CallTarget { + Address target; + bool is_new_temporary = false; + GDScriptByteCodeGenerator *codegen = nullptr; +#ifdef DEV_ENABLED + bool cleaned = false; +#endif + + void cleanup() { + DEV_ASSERT(!cleaned); + if (is_new_temporary) { + codegen->pop_temporary(); + } +#ifdef DEV_ENABLED + cleaned = true; +#endif + } + + CallTarget(Address p_target, bool p_is_new_temporary, GDScriptByteCodeGenerator *p_codegen) : + target(p_target), + is_new_temporary(p_is_new_temporary), + codegen(p_codegen) {} + ~CallTarget() { DEV_ASSERT(cleaned); } + CallTarget(const CallTarget &) = delete; + CallTarget &operator=(CallTarget &) = delete; + }; + bool ended = false; GDScriptFunction *function = nullptr; bool debug_stack = false; @@ -326,7 +353,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { } } - Address get_call_target(const Address &p_target, Variant::Type p_type = Variant::NIL); + CallTarget get_call_target(const Address &p_target, Variant::Type p_type = Variant::NIL); int address_of(const Address &p_address) { switch (p_address.mode) { diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index b9576ee517..ba400b8e15 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -1281,21 +1281,19 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } - bool was_freed = false; - Object *src_obj = src->get_validated_object_with_check(was_freed); - if (!src_obj) { - if (was_freed) { + if (src->get_type() == Variant::OBJECT) { + bool was_freed = false; + Object *src_obj = src->get_validated_object_with_check(was_freed); + if (!src_obj && was_freed) { err_text = "Trying to assign invalid previously freed instance."; - } else { - err_text = "Trying to assign invalid null variable."; + OPCODE_BREAK; } - OPCODE_BREAK; - } - if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) { - err_text = "Trying to assign value of type '" + src_obj->get_class_name() + - "' to a variable of type '" + nc->get_name() + "'."; - OPCODE_BREAK; + if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) { + err_text = "Trying to assign value of type '" + src_obj->get_class_name() + + "' to a variable of type '" + nc->get_name() + "'."; + OPCODE_BREAK; + } } #endif // DEBUG_ENABLED *dst = *src; @@ -1320,15 +1318,11 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } - if (src->get_type() != Variant::NIL) { + if (src->get_type() == Variant::OBJECT) { bool was_freed = false; Object *val_obj = src->get_validated_object_with_check(was_freed); - if (!val_obj) { - if (was_freed) { - err_text = "Trying to assign invalid previously freed instance."; - } else { - err_text = "Trying to assign invalid null variable."; - } + if (!val_obj && was_freed) { + err_text = "Trying to assign invalid previously freed instance."; OPCODE_BREAK; } diff --git a/modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.gd b/modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.gd new file mode 100644 index 0000000000..c197062d9f --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.gd @@ -0,0 +1,15 @@ +extends Node + +func test(): + var typed: Variant = get_node_or_null("does_not_exist") + var untyped = null + var node_1: Node = typed + var node_2: Node = untyped + var node_3 = typed + var node_4 = untyped + print(typed) + print(untyped) + print(node_1) + print(node_2) + print(node_3) + print(node_4) diff --git a/modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.out b/modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.out new file mode 100644 index 0000000000..d66b72f5c3 --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.out @@ -0,0 +1,7 @@ +GDTEST_OK +<Object#null> +<null> +<Object#null> +<null> +<Object#null> +<null> diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs index 060c01b3f9..c267d32f5a 100644 --- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs +++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs @@ -279,7 +279,7 @@ namespace GodotTools if (line >= 0) { args.Add("-g"); - args.Add($"{scriptPath}:{line}:{col}"); + args.Add($"{scriptPath}:{line + 1}:{col + 1}"); } else { |