summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp2
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp103
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h29
-rw-r--r--modules/gdscript/gdscript_vm.cpp32
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.gd15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/native_typed_assign_null.out7
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs2
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
{