diff options
Diffstat (limited to 'modules/gdscript/gdscript_byte_codegen.cpp')
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 376 |
1 files changed, 230 insertions, 146 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index 6c80fb7665..1414075ba8 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -69,56 +69,52 @@ uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) { uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type) { Variant::Type temp_type = Variant::NIL; - if (p_type.has_type) { - if (p_type.kind == GDScriptDataType::BUILTIN) { - switch (p_type.builtin_type) { - case Variant::NIL: - case Variant::BOOL: - case Variant::INT: - case Variant::FLOAT: - case Variant::STRING: - case Variant::VECTOR2: - case Variant::VECTOR2I: - case Variant::RECT2: - case Variant::RECT2I: - case Variant::VECTOR3: - case Variant::VECTOR3I: - case Variant::TRANSFORM2D: - case Variant::VECTOR4: - case Variant::VECTOR4I: - case Variant::PLANE: - case Variant::QUATERNION: - case Variant::AABB: - case Variant::BASIS: - case Variant::TRANSFORM3D: - case Variant::PROJECTION: - case Variant::COLOR: - case Variant::STRING_NAME: - case Variant::NODE_PATH: - case Variant::RID: - case Variant::OBJECT: - case Variant::CALLABLE: - case Variant::SIGNAL: - case Variant::DICTIONARY: - case Variant::ARRAY: - temp_type = p_type.builtin_type; - break; - case Variant::PACKED_BYTE_ARRAY: - case Variant::PACKED_INT32_ARRAY: - case Variant::PACKED_INT64_ARRAY: - case Variant::PACKED_FLOAT32_ARRAY: - case Variant::PACKED_FLOAT64_ARRAY: - case Variant::PACKED_STRING_ARRAY: - case Variant::PACKED_VECTOR2_ARRAY: - case Variant::PACKED_VECTOR3_ARRAY: - case Variant::PACKED_COLOR_ARRAY: - case Variant::VARIANT_MAX: - // Packed arrays are reference counted, so we don't use the pool for them. - temp_type = Variant::NIL; - break; - } - } else { - temp_type = Variant::OBJECT; + if (p_type.has_type && p_type.kind == GDScriptDataType::BUILTIN) { + switch (p_type.builtin_type) { + case Variant::NIL: + case Variant::BOOL: + case Variant::INT: + case Variant::FLOAT: + case Variant::STRING: + case Variant::VECTOR2: + case Variant::VECTOR2I: + case Variant::RECT2: + case Variant::RECT2I: + case Variant::VECTOR3: + case Variant::VECTOR3I: + case Variant::TRANSFORM2D: + case Variant::VECTOR4: + case Variant::VECTOR4I: + case Variant::PLANE: + case Variant::QUATERNION: + case Variant::AABB: + case Variant::BASIS: + case Variant::TRANSFORM3D: + case Variant::PROJECTION: + case Variant::COLOR: + case Variant::STRING_NAME: + case Variant::NODE_PATH: + case Variant::RID: + case Variant::CALLABLE: + case Variant::SIGNAL: + temp_type = p_type.builtin_type; + break; + case Variant::OBJECT: + case Variant::DICTIONARY: + case Variant::ARRAY: + case Variant::PACKED_BYTE_ARRAY: + case Variant::PACKED_INT32_ARRAY: + case Variant::PACKED_INT64_ARRAY: + case Variant::PACKED_FLOAT32_ARRAY: + case Variant::PACKED_FLOAT64_ARRAY: + case Variant::PACKED_STRING_ARRAY: + case Variant::PACKED_VECTOR2_ARRAY: + case Variant::PACKED_VECTOR3_ARRAY: + case Variant::PACKED_COLOR_ARRAY: + case Variant::VARIANT_MAX: + // Arrays, dictionaries, and objects are reference counted, so we don't use the pool for them. + temp_type = Variant::NIL; + break; } } @@ -143,6 +139,13 @@ 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::NIL) { + // Avoid keeping in the stack long-lived references to objects, + // which may prevent RefCounted objects from being freed. + // However, the cleanup will be performed an the end of the + // statement, to allow object references to survive chaining. + temporaries_pending_clear.push_back(slot_idx); + } temporaries_pool[slot.type].push_back(slot_idx); used_temporaries.pop_back(); } @@ -401,6 +404,16 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { function->_instruction_args_size = instr_args_max; function->_ptrcall_args_size = ptrcall_max; +#ifdef DEBUG_ENABLED + function->operator_names = operator_names; + function->setter_names = setter_names; + function->getter_names = getter_names; + function->builtin_methods_names = builtin_methods_names; + function->constructors_names = constructors_names; + function->utilities_names = utilities_names; + function->gds_utilities_names = gds_utilities_names; +#endif + ended = true; return function; } @@ -551,6 +564,9 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va append(Address()); append(p_target); append(op_func); +#ifdef DEBUG_ENABLED + add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator)); +#endif return; } @@ -563,7 +579,8 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va } void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { - if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) { + // Avoid validated evaluator for modulo and division when operands are int, since there's no check for division by zero. + if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand) && ((p_operator != Variant::OP_DIVIDE && p_operator != Variant::OP_MODULE) || p_left_operand.type.builtin_type != Variant::INT || p_right_operand.type.builtin_type != Variant::INT)) { if (p_target.mode == Address::TEMPORARY) { Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type); Variant::Type temp_type = temporaries[p_target.address].type; @@ -580,6 +597,9 @@ void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, V append(p_right_operand); append(p_target); append(op_func); +#ifdef DEBUG_ENABLED + add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator)); +#endif return; } @@ -591,18 +611,44 @@ void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, V append(p_operator); } -void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const Address &p_type) { - append_opcode(GDScriptFunction::OPCODE_EXTENDS_TEST); - append(p_source); - append(p_type); - append(p_target); -} - -void GDScriptByteCodeGenerator::write_type_test_builtin(const Address &p_target, const Address &p_source, Variant::Type p_type) { - append_opcode(GDScriptFunction::OPCODE_IS_BUILTIN); - append(p_source); - append(p_target); - append(p_type); +void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) { + switch (p_type.kind) { + case GDScriptDataType::BUILTIN: { + if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type()) { + const GDScriptDataType &element_type = p_type.get_container_element_type(); + append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_ARRAY); + append(p_target); + append(p_source); + append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); + append(element_type.builtin_type); + append(element_type.native_type); + } else { + append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_BUILTIN); + append(p_target); + append(p_source); + append(p_type.builtin_type); + } + } break; + case GDScriptDataType::NATIVE: { + append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_NATIVE); + append(p_target); + append(p_source); + append(p_type.native_type); + } break; + case GDScriptDataType::SCRIPT: + case GDScriptDataType::GDSCRIPT: { + const Variant &script = p_type.script_type; + append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_SCRIPT); + append(p_target); + append(p_source); + append(get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); + } break; + default: { + ERR_PRINT("Compiler bug: unresolved type in type test."); + append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE); + append(p_target); + } + } } void GDScriptByteCodeGenerator::write_and_left_operand(const Address &p_left_operand) { @@ -765,6 +811,9 @@ void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const S append(p_target); append(p_source); append(setter); +#ifdef DEBUG_ENABLED + add_debug_name(setter_names, get_setter_pos(setter), p_name); +#endif return; } append_opcode(GDScriptFunction::OPCODE_SET_NAMED); @@ -780,6 +829,9 @@ void GDScriptByteCodeGenerator::write_get_named(const Address &p_target, const S append(p_source); append(p_target); append(getter); +#ifdef DEBUG_ENABLED + add_debug_name(getter_names, get_getter_pos(getter), p_name); +#endif return; } append_opcode(GDScriptFunction::OPCODE_GET_NAMED); @@ -804,9 +856,13 @@ void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_ta switch (p_target.type.kind) { case GDScriptDataType::BUILTIN: { if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { + const GDScriptDataType &element_type = p_target.type.get_container_element_type(); append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY); append(p_target); append(p_source); + append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); + append(element_type.builtin_type); + append(element_type.native_type); } else { append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); append(p_target); @@ -846,9 +902,13 @@ void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_ta void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) { if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type()) { + const GDScriptDataType &element_type = p_target.type.get_container_element_type(); append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY); append(p_target); append(p_source); + append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); + append(element_type.builtin_type); + append(element_type.native_type); } else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) { // Need conversion. append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN); @@ -924,7 +984,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) { @@ -933,10 +993,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); } } @@ -946,9 +1005,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) { @@ -956,9 +1017,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) { @@ -967,25 +1030,33 @@ 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, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) { +void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) { append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size()); + GDScriptUtilityFunctions::FunctionPtr gds_function = GDScriptUtilityFunctions::get_function(p_function); 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); + append(gds_function); + ct.cleanup(); +#ifdef DEBUG_ENABLED + add_debug_name(gds_utilities_names, get_gds_utility_pos(gds_function), p_function); +#endif } void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) { bool is_validated = true; if (Variant::is_utility_function_vararg(p_function)) { - is_validated = true; // Vararg works fine with any argument, since they can be any type. + is_validated = false; // Vararg needs runtime checks, can't use validated call. } else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) { bool all_types_exact = true; for (int i = 0; i < p_arguments.size(); i++) { @@ -1000,26 +1071,32 @@ 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 } else { append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size()); 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(); } } @@ -1028,7 +1105,7 @@ void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, // Check if all types are correct. if (Variant::is_builtin_method_vararg(p_type, p_method)) { - is_validated = true; // Vararg works fine with any argument, since they can be any type. + is_validated = false; // Vararg needs runtime checks, can't use validated call. } else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) { bool all_types_exact = true; for (int i = 0; i < p_arguments.size(); i++) { @@ -1048,10 +1125,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); } @@ -1059,10 +1138,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()); @@ -1071,9 +1150,14 @@ 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 } void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) { @@ -1095,9 +1179,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; } } @@ -1107,10 +1193,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) { @@ -1172,9 +1260,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()); } @@ -1188,9 +1278,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) { @@ -1199,9 +1291,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) { @@ -1210,9 +1304,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) { @@ -1221,9 +1317,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) { @@ -1260,9 +1358,14 @@ 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 return; } } @@ -1271,9 +1374,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) { @@ -1281,8 +1386,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) { @@ -1290,18 +1397,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)); - if (p_element_type.script_type) { - Variant script_type = Ref<Script>(p_element_type.script_type); - int addr = get_constant_pos(script_type); - addr |= GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS; - append(addr); - } else { - append(Address()); // null. - } + 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) { @@ -1309,8 +1411,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) { @@ -1543,28 +1647,6 @@ void GDScriptByteCodeGenerator::write_endwhile() { current_breaks_to_patch.pop_back(); } -void GDScriptByteCodeGenerator::start_match() { - match_continues_to_patch.push_back(List<int>()); -} - -void GDScriptByteCodeGenerator::start_match_branch() { - // Patch continue statements. - for (const int &E : match_continues_to_patch.back()->get()) { - patch_jump(E); - } - match_continues_to_patch.pop_back(); - // Start a new list for next branch. - match_continues_to_patch.push_back(List<int>()); -} - -void GDScriptByteCodeGenerator::end_match() { - // Patch continue statements. - for (const int &E : match_continues_to_patch.back()->get()) { - patch_jump(E); - } - match_continues_to_patch.pop_back(); -} - void GDScriptByteCodeGenerator::write_break() { append_opcode(GDScriptFunction::OPCODE_JUMP); current_breaks_to_patch.back()->get().push_back(opcodes.size()); @@ -1576,12 +1658,6 @@ void GDScriptByteCodeGenerator::write_continue() { append(continue_addrs.back()->get()); } -void GDScriptByteCodeGenerator::write_continue_match() { - append_opcode(GDScriptFunction::OPCODE_JUMP); - match_continues_to_patch.back()->get().push_back(opcodes.size()); - append(0); -} - void GDScriptByteCodeGenerator::write_breakpoint() { append_opcode(GDScriptFunction::OPCODE_BREAKPOINT); } @@ -1601,14 +1677,10 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) { if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { // Typed array. const GDScriptDataType &element_type = function->return_type.get_container_element_type(); - - Variant script = element_type.script_type; - int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); - append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY); append(p_return_value); - append(script_idx); - append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT); + append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); + append(element_type.builtin_type); append(element_type.native_type); } else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) { // Add conversion. @@ -1629,15 +1701,10 @@ void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) { case GDScriptDataType::BUILTIN: { if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) { const GDScriptDataType &element_type = function->return_type.get_container_element_type(); - - Variant script = function->return_type.script_type; - int script_idx = get_constant_pos(script); - script_idx |= (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS); - append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY); append(p_return_value); - append(script_idx); - append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT); + append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS)); + append(element_type.builtin_type); append(element_type.native_type); } else { append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN); @@ -1687,6 +1754,23 @@ void GDScriptByteCodeGenerator::end_block() { pop_stack_identifiers(); } +void GDScriptByteCodeGenerator::clean_temporaries() { + List<int>::Element *E = temporaries_pending_clear.front(); + while (E) { + // The temporary may have been re-used as something else than an object + // since it was added to the list. In that case, there's no need to clear it. + int slot_idx = E->get(); + const StackSlot &slot = temporaries[slot_idx]; + if (slot.type == Variant::NIL) { + write_assign_false(Address(Address::TEMPORARY, slot_idx)); + } + + List<int>::Element *next = E->next(); + E->erase(); + E = next; + } +} + GDScriptByteCodeGenerator::~GDScriptByteCodeGenerator() { if (!ended && function != nullptr) { memdelete(function); |