Path: blob/master/modules/gdscript/gdscript_byte_codegen.cpp
20841 views
/**************************************************************************/1/* gdscript_byte_codegen.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "gdscript_byte_codegen.h"3132#include "core/debugger/engine_debugger.h"3334uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) {35function->_argument_count++;36function->argument_types.push_back(p_type);37if (p_is_optional) {38function->_default_arg_count++;39}4041return add_local(p_name, p_type);42}4344uint32_t GDScriptByteCodeGenerator::add_local(const StringName &p_name, const GDScriptDataType &p_type) {45int stack_pos = locals.size() + GDScriptFunction::FIXED_ADDRESSES_MAX;46locals.push_back(StackSlot(p_type.builtin_type, p_type.can_contain_object()));47add_stack_identifier(p_name, stack_pos);48return stack_pos;49}5051uint32_t GDScriptByteCodeGenerator::add_local_constant(const StringName &p_name, const Variant &p_constant) {52int index = add_or_get_constant(p_constant);53local_constants[p_name] = index;54return index;55}5657uint32_t GDScriptByteCodeGenerator::add_or_get_constant(const Variant &p_constant) {58return get_constant_pos(p_constant);59}6061uint32_t GDScriptByteCodeGenerator::add_or_get_name(const StringName &p_name) {62return get_name_map_pos(p_name);63}6465uint32_t GDScriptByteCodeGenerator::add_temporary(const GDScriptDataType &p_type) {66Variant::Type temp_type = Variant::NIL;67if (p_type.kind == GDScriptDataType::BUILTIN) {68switch (p_type.builtin_type) {69case Variant::NIL:70case Variant::BOOL:71case Variant::INT:72case Variant::FLOAT:73case Variant::STRING:74case Variant::VECTOR2:75case Variant::VECTOR2I:76case Variant::RECT2:77case Variant::RECT2I:78case Variant::VECTOR3:79case Variant::VECTOR3I:80case Variant::TRANSFORM2D:81case Variant::VECTOR4:82case Variant::VECTOR4I:83case Variant::PLANE:84case Variant::QUATERNION:85case Variant::AABB:86case Variant::BASIS:87case Variant::TRANSFORM3D:88case Variant::PROJECTION:89case Variant::COLOR:90case Variant::STRING_NAME:91case Variant::NODE_PATH:92case Variant::RID:93case Variant::CALLABLE:94case Variant::SIGNAL:95temp_type = p_type.builtin_type;96break;97case Variant::OBJECT:98case Variant::DICTIONARY:99case Variant::ARRAY:100case Variant::PACKED_BYTE_ARRAY:101case Variant::PACKED_INT32_ARRAY:102case Variant::PACKED_INT64_ARRAY:103case Variant::PACKED_FLOAT32_ARRAY:104case Variant::PACKED_FLOAT64_ARRAY:105case Variant::PACKED_STRING_ARRAY:106case Variant::PACKED_VECTOR2_ARRAY:107case Variant::PACKED_VECTOR3_ARRAY:108case Variant::PACKED_COLOR_ARRAY:109case Variant::PACKED_VECTOR4_ARRAY:110case Variant::VARIANT_MAX:111// Arrays, dictionaries, and objects are reference counted, so we don't use the pool for them.112temp_type = Variant::NIL;113break;114}115}116117if (!temporaries_pool.has(temp_type)) {118temporaries_pool[temp_type] = List<int>();119}120121List<int> &pool = temporaries_pool[temp_type];122if (pool.is_empty()) {123StackSlot new_temp(temp_type, p_type.can_contain_object());124int idx = temporaries.size();125pool.push_back(idx);126temporaries.push_back(new_temp);127}128int slot = pool.front()->get();129pool.pop_front();130used_temporaries.push_back(slot);131return slot;132}133134void GDScriptByteCodeGenerator::pop_temporary() {135ERR_FAIL_COND(used_temporaries.is_empty());136int slot_idx = used_temporaries.back()->get();137if (temporaries[slot_idx].can_contain_object) {138// Avoid keeping in the stack long-lived references to objects,139// which may prevent `RefCounted` objects from being freed.140// However, the cleanup will be performed an the end of the141// statement, to allow object references to survive chaining.142temporaries_pending_clear.insert(slot_idx);143}144temporaries_pool[temporaries[slot_idx].type].push_back(slot_idx);145used_temporaries.pop_back();146}147148void GDScriptByteCodeGenerator::start_parameters() {149if (function->_default_arg_count > 0) {150append(GDScriptFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);151function->default_arguments.push_back(opcodes.size());152}153}154155void GDScriptByteCodeGenerator::end_parameters() {156function->default_arguments.reverse();157}158159void GDScriptByteCodeGenerator::write_start(GDScript *p_script, const StringName &p_function_name, bool p_static, Variant p_rpc_config, const GDScriptDataType &p_return_type) {160function = memnew(GDScriptFunction);161162function->name = p_function_name;163function->_script = p_script;164function->source = p_script->get_script_path();165166#ifdef DEBUG_ENABLED167function->func_cname = (String(function->source) + " - " + String(p_function_name)).utf8();168function->_func_cname = function->func_cname.get_data();169#endif170171function->_static = p_static;172function->return_type = p_return_type;173function->rpc_config = p_rpc_config;174function->_argument_count = 0;175}176177GDScriptFunction *GDScriptByteCodeGenerator::write_end() {178#ifdef DEBUG_ENABLED179if (!used_temporaries.is_empty()) {180ERR_PRINT("Non-zero temporary variables at end of function: " + itos(used_temporaries.size()));181}182#endif183append_opcode(GDScriptFunction::OPCODE_END);184185for (int i = 0; i < temporaries.size(); i++) {186int stack_index = i + max_locals + GDScriptFunction::FIXED_ADDRESSES_MAX;187for (int j = 0; j < temporaries[i].bytecode_indices.size(); j++) {188opcodes.write[temporaries[i].bytecode_indices[j]] = stack_index | (GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);189}190if (temporaries[i].type != Variant::NIL) {191function->temporary_slots[stack_index] = temporaries[i].type;192}193}194195if (constant_map.size()) {196function->_constant_count = constant_map.size();197function->constants.resize(constant_map.size());198function->_constants_ptr = function->constants.ptrw();199for (const KeyValue<Variant, int> &K : constant_map) {200function->constants.write[K.value] = K.key;201}202for (const KeyValue<StringName, int> &K : local_constants) {203function->constant_map.insert(K.key, function->constants[K.value]);204}205} else {206function->_constants_ptr = nullptr;207function->_constant_count = 0;208}209210if (name_map.size()) {211function->global_names.resize(name_map.size());212function->_global_names_ptr = &function->global_names[0];213for (const KeyValue<StringName, int> &E : name_map) {214function->global_names.write[E.value] = E.key;215}216function->_global_names_count = function->global_names.size();217218} else {219function->_global_names_ptr = nullptr;220function->_global_names_count = 0;221}222223if (opcodes.size()) {224function->code = opcodes;225function->_code_ptr = &function->code.write[0];226function->_code_size = opcodes.size();227228} else {229function->_code_ptr = nullptr;230function->_code_size = 0;231}232233if (function->default_arguments.size()) {234function->_default_arg_count = function->default_arguments.size() - 1;235function->_default_arg_ptr = &function->default_arguments[0];236} else {237function->_default_arg_count = 0;238function->_default_arg_ptr = nullptr;239}240241if (operator_func_map.size()) {242function->operator_funcs.resize(operator_func_map.size());243function->_operator_funcs_count = function->operator_funcs.size();244function->_operator_funcs_ptr = function->operator_funcs.ptr();245for (const KeyValue<Variant::ValidatedOperatorEvaluator, int> &E : operator_func_map) {246function->operator_funcs.write[E.value] = E.key;247}248} else {249function->_operator_funcs_count = 0;250function->_operator_funcs_ptr = nullptr;251}252253if (setters_map.size()) {254function->setters.resize(setters_map.size());255function->_setters_count = function->setters.size();256function->_setters_ptr = function->setters.ptr();257for (const KeyValue<Variant::ValidatedSetter, int> &E : setters_map) {258function->setters.write[E.value] = E.key;259}260} else {261function->_setters_count = 0;262function->_setters_ptr = nullptr;263}264265if (getters_map.size()) {266function->getters.resize(getters_map.size());267function->_getters_count = function->getters.size();268function->_getters_ptr = function->getters.ptr();269for (const KeyValue<Variant::ValidatedGetter, int> &E : getters_map) {270function->getters.write[E.value] = E.key;271}272} else {273function->_getters_count = 0;274function->_getters_ptr = nullptr;275}276277if (keyed_setters_map.size()) {278function->keyed_setters.resize(keyed_setters_map.size());279function->_keyed_setters_count = function->keyed_setters.size();280function->_keyed_setters_ptr = function->keyed_setters.ptr();281for (const KeyValue<Variant::ValidatedKeyedSetter, int> &E : keyed_setters_map) {282function->keyed_setters.write[E.value] = E.key;283}284} else {285function->_keyed_setters_count = 0;286function->_keyed_setters_ptr = nullptr;287}288289if (keyed_getters_map.size()) {290function->keyed_getters.resize(keyed_getters_map.size());291function->_keyed_getters_count = function->keyed_getters.size();292function->_keyed_getters_ptr = function->keyed_getters.ptr();293for (const KeyValue<Variant::ValidatedKeyedGetter, int> &E : keyed_getters_map) {294function->keyed_getters.write[E.value] = E.key;295}296} else {297function->_keyed_getters_count = 0;298function->_keyed_getters_ptr = nullptr;299}300301if (indexed_setters_map.size()) {302function->indexed_setters.resize(indexed_setters_map.size());303function->_indexed_setters_count = function->indexed_setters.size();304function->_indexed_setters_ptr = function->indexed_setters.ptr();305for (const KeyValue<Variant::ValidatedIndexedSetter, int> &E : indexed_setters_map) {306function->indexed_setters.write[E.value] = E.key;307}308} else {309function->_indexed_setters_count = 0;310function->_indexed_setters_ptr = nullptr;311}312313if (indexed_getters_map.size()) {314function->indexed_getters.resize(indexed_getters_map.size());315function->_indexed_getters_count = function->indexed_getters.size();316function->_indexed_getters_ptr = function->indexed_getters.ptr();317for (const KeyValue<Variant::ValidatedIndexedGetter, int> &E : indexed_getters_map) {318function->indexed_getters.write[E.value] = E.key;319}320} else {321function->_indexed_getters_count = 0;322function->_indexed_getters_ptr = nullptr;323}324325if (builtin_method_map.size()) {326function->builtin_methods.resize(builtin_method_map.size());327function->_builtin_methods_ptr = function->builtin_methods.ptr();328function->_builtin_methods_count = builtin_method_map.size();329for (const KeyValue<Variant::ValidatedBuiltInMethod, int> &E : builtin_method_map) {330function->builtin_methods.write[E.value] = E.key;331}332} else {333function->_builtin_methods_ptr = nullptr;334function->_builtin_methods_count = 0;335}336337if (constructors_map.size()) {338function->constructors.resize(constructors_map.size());339function->_constructors_ptr = function->constructors.ptr();340function->_constructors_count = constructors_map.size();341for (const KeyValue<Variant::ValidatedConstructor, int> &E : constructors_map) {342function->constructors.write[E.value] = E.key;343}344} else {345function->_constructors_ptr = nullptr;346function->_constructors_count = 0;347}348349if (utilities_map.size()) {350function->utilities.resize(utilities_map.size());351function->_utilities_ptr = function->utilities.ptr();352function->_utilities_count = utilities_map.size();353for (const KeyValue<Variant::ValidatedUtilityFunction, int> &E : utilities_map) {354function->utilities.write[E.value] = E.key;355}356} else {357function->_utilities_ptr = nullptr;358function->_utilities_count = 0;359}360361if (gds_utilities_map.size()) {362function->gds_utilities.resize(gds_utilities_map.size());363function->_gds_utilities_ptr = function->gds_utilities.ptr();364function->_gds_utilities_count = gds_utilities_map.size();365for (const KeyValue<GDScriptUtilityFunctions::FunctionPtr, int> &E : gds_utilities_map) {366function->gds_utilities.write[E.value] = E.key;367}368} else {369function->_gds_utilities_ptr = nullptr;370function->_gds_utilities_count = 0;371}372373if (method_bind_map.size()) {374function->methods.resize(method_bind_map.size());375function->_methods_ptr = function->methods.ptrw();376function->_methods_count = method_bind_map.size();377for (const KeyValue<MethodBind *, int> &E : method_bind_map) {378function->methods.write[E.value] = E.key;379}380} else {381function->_methods_ptr = nullptr;382function->_methods_count = 0;383}384385if (lambdas_map.size()) {386function->lambdas.resize(lambdas_map.size());387function->_lambdas_ptr = function->lambdas.ptrw();388function->_lambdas_count = lambdas_map.size();389for (const KeyValue<GDScriptFunction *, int> &E : lambdas_map) {390function->lambdas.write[E.value] = E.key;391}392} else {393function->_lambdas_ptr = nullptr;394function->_lambdas_count = 0;395}396397if (GDScriptLanguage::get_singleton()->should_track_locals()) {398function->stack_debug = stack_debug;399}400function->_stack_size = GDScriptFunction::FIXED_ADDRESSES_MAX + max_locals + temporaries.size();401function->_instruction_args_size = instr_args_max;402403#ifdef DEBUG_ENABLED404function->operator_names = operator_names;405function->setter_names = setter_names;406function->getter_names = getter_names;407function->builtin_methods_names = builtin_methods_names;408function->constructors_names = constructors_names;409function->utilities_names = utilities_names;410function->gds_utilities_names = gds_utilities_names;411#endif412413ended = true;414return function;415}416417#ifdef DEBUG_ENABLED418void GDScriptByteCodeGenerator::set_signature(const String &p_signature) {419function->profile.signature = p_signature;420}421#endif422423void GDScriptByteCodeGenerator::set_initial_line(int p_line) {424function->_initial_line = p_line;425}426427#define HAS_BUILTIN_TYPE(m_var) \428(m_var.type.kind == GDScriptDataType::BUILTIN)429430#define IS_BUILTIN_TYPE(m_var, m_type) \431(m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type && m_type != Variant::NIL)432433void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Variant::Type p_new_type) {434switch (p_new_type) {435case Variant::BOOL:436append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_BOOL);437break;438case Variant::INT:439append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_INT);440break;441case Variant::FLOAT:442append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_FLOAT);443break;444case Variant::STRING:445append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING);446break;447case Variant::VECTOR2:448append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2);449break;450case Variant::VECTOR2I:451append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2I);452break;453case Variant::RECT2:454append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2);455break;456case Variant::RECT2I:457append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2I);458break;459case Variant::VECTOR3:460append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3);461break;462case Variant::VECTOR3I:463append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3I);464break;465case Variant::TRANSFORM2D:466append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM2D);467break;468case Variant::VECTOR4:469append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3);470break;471case Variant::VECTOR4I:472append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3I);473break;474case Variant::PLANE:475append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PLANE);476break;477case Variant::QUATERNION:478append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_QUATERNION);479break;480case Variant::AABB:481append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_AABB);482break;483case Variant::BASIS:484append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS);485break;486case Variant::TRANSFORM3D:487append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM3D);488break;489case Variant::PROJECTION:490append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PROJECTION);491break;492case Variant::COLOR:493append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR);494break;495case Variant::STRING_NAME:496append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING_NAME);497break;498case Variant::NODE_PATH:499append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_NODE_PATH);500break;501case Variant::RID:502append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_RID);503break;504case Variant::OBJECT:505append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_OBJECT);506break;507case Variant::CALLABLE:508append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_CALLABLE);509break;510case Variant::SIGNAL:511append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_SIGNAL);512break;513case Variant::DICTIONARY:514append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_DICTIONARY);515break;516case Variant::ARRAY:517append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_ARRAY);518break;519case Variant::PACKED_BYTE_ARRAY:520append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY);521break;522case Variant::PACKED_INT32_ARRAY:523append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY);524break;525case Variant::PACKED_INT64_ARRAY:526append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY);527break;528case Variant::PACKED_FLOAT32_ARRAY:529append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY);530break;531case Variant::PACKED_FLOAT64_ARRAY:532append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY);533break;534case Variant::PACKED_STRING_ARRAY:535append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY);536break;537case Variant::PACKED_VECTOR2_ARRAY:538append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY);539break;540case Variant::PACKED_VECTOR3_ARRAY:541append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY);542break;543case Variant::PACKED_COLOR_ARRAY:544append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY);545break;546case Variant::PACKED_VECTOR4_ARRAY:547append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY);548break;549case Variant::NIL:550case Variant::VARIANT_MAX:551return;552}553append(p_target);554}555556void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) {557if (HAS_BUILTIN_TYPE(p_left_operand)) {558// Gather specific operator.559Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, Variant::NIL);560561append_opcode(GDScriptFunction::OPCODE_OPERATOR_VALIDATED);562append(p_left_operand);563append(Address());564append(p_target);565append(op_func);566#ifdef DEBUG_ENABLED567add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator));568#endif569return;570}571572// No specific types, perform variant evaluation.573append_opcode(GDScriptFunction::OPCODE_OPERATOR);574append(p_left_operand);575append(Address());576append(p_target);577append(p_operator);578append(0); // Signature storage.579append(0); // Return type storage.580constexpr int _pointer_size = sizeof(Variant::ValidatedOperatorEvaluator) / sizeof(*(opcodes.ptr()));581for (int i = 0; i < _pointer_size; i++) {582append(0); // Space for function pointer.583}584}585586void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {587bool valid = HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand);588589// Avoid validated evaluator for modulo and division when operands are int or integer vector, since there's no check for division by zero.590if (valid && (p_operator == Variant::OP_DIVIDE || p_operator == Variant::OP_MODULE)) {591switch (p_left_operand.type.builtin_type) {592case Variant::INT:593// Cannot use modulo between int / float, we should raise an error later in GDScript594valid = p_right_operand.type.builtin_type != Variant::INT && p_operator == Variant::OP_DIVIDE;595break;596case Variant::VECTOR2I:597case Variant::VECTOR3I:598case Variant::VECTOR4I:599valid = p_right_operand.type.builtin_type != Variant::INT && p_right_operand.type.builtin_type != p_left_operand.type.builtin_type;600break;601default:602break;603}604}605606if (valid) {607if (p_target.mode == Address::TEMPORARY) {608Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);609Variant::Type temp_type = temporaries[p_target.address].type;610if (result_type != temp_type) {611write_type_adjust(p_target, result_type);612}613}614615// Gather specific operator.616Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);617618append_opcode(GDScriptFunction::OPCODE_OPERATOR_VALIDATED);619append(p_left_operand);620append(p_right_operand);621append(p_target);622append(op_func);623#ifdef DEBUG_ENABLED624add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator));625#endif626return;627}628629// No specific types, perform variant evaluation.630append_opcode(GDScriptFunction::OPCODE_OPERATOR);631append(p_left_operand);632append(p_right_operand);633append(p_target);634append(p_operator);635append(0); // Signature storage.636append(0); // Return type storage.637constexpr int _pointer_size = sizeof(Variant::ValidatedOperatorEvaluator) / sizeof(*(opcodes.ptr()));638for (int i = 0; i < _pointer_size; i++) {639append(0); // Space for function pointer.640}641}642643void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {644switch (p_type.kind) {645case GDScriptDataType::BUILTIN: {646if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type(0)) {647const GDScriptDataType &element_type = p_type.get_container_element_type(0);648append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_ARRAY);649append(p_target);650append(p_source);651append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));652append(element_type.builtin_type);653append(element_type.native_type);654} else if (p_type.builtin_type == Variant::DICTIONARY && p_type.has_container_element_types()) {655const GDScriptDataType &key_element_type = p_type.get_container_element_type_or_variant(0);656const GDScriptDataType &value_element_type = p_type.get_container_element_type_or_variant(1);657append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_DICTIONARY);658append(p_target);659append(p_source);660append(get_constant_pos(key_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));661append(get_constant_pos(value_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));662append(key_element_type.builtin_type);663append(key_element_type.native_type);664append(value_element_type.builtin_type);665append(value_element_type.native_type);666} else {667append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_BUILTIN);668append(p_target);669append(p_source);670append(p_type.builtin_type);671}672} break;673case GDScriptDataType::NATIVE: {674append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_NATIVE);675append(p_target);676append(p_source);677append(p_type.native_type);678} break;679case GDScriptDataType::SCRIPT:680case GDScriptDataType::GDSCRIPT: {681const Variant &script = p_type.script_type;682append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_SCRIPT);683append(p_target);684append(p_source);685append(get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));686} break;687default: {688ERR_PRINT("Compiler bug: unresolved type in type test.");689append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);690append(p_target);691}692}693}694695void GDScriptByteCodeGenerator::write_and_left_operand(const Address &p_left_operand) {696append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);697append(p_left_operand);698logic_op_jump_pos1.push_back(opcodes.size());699append(0); // Jump target, will be patched.700}701702void GDScriptByteCodeGenerator::write_and_right_operand(const Address &p_right_operand) {703append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);704append(p_right_operand);705logic_op_jump_pos2.push_back(opcodes.size());706append(0); // Jump target, will be patched.707}708709void GDScriptByteCodeGenerator::write_end_and(const Address &p_target) {710// If here means both operands are true.711append_opcode(GDScriptFunction::OPCODE_ASSIGN_TRUE);712append(p_target);713// Jump away from the fail condition.714append_opcode(GDScriptFunction::OPCODE_JUMP);715append(opcodes.size() + 3);716// Here it means one of operands is false.717patch_jump(logic_op_jump_pos1.back()->get());718patch_jump(logic_op_jump_pos2.back()->get());719logic_op_jump_pos1.pop_back();720logic_op_jump_pos2.pop_back();721append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);722append(p_target);723}724725void GDScriptByteCodeGenerator::write_or_left_operand(const Address &p_left_operand) {726append_opcode(GDScriptFunction::OPCODE_JUMP_IF);727append(p_left_operand);728logic_op_jump_pos1.push_back(opcodes.size());729append(0); // Jump target, will be patched.730}731732void GDScriptByteCodeGenerator::write_or_right_operand(const Address &p_right_operand) {733append_opcode(GDScriptFunction::OPCODE_JUMP_IF);734append(p_right_operand);735logic_op_jump_pos2.push_back(opcodes.size());736append(0); // Jump target, will be patched.737}738739void GDScriptByteCodeGenerator::write_end_or(const Address &p_target) {740// If here means both operands are false.741append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);742append(p_target);743// Jump away from the success condition.744append_opcode(GDScriptFunction::OPCODE_JUMP);745append(opcodes.size() + 3);746// Here it means one of operands is true.747patch_jump(logic_op_jump_pos1.back()->get());748patch_jump(logic_op_jump_pos2.back()->get());749logic_op_jump_pos1.pop_back();750logic_op_jump_pos2.pop_back();751append_opcode(GDScriptFunction::OPCODE_ASSIGN_TRUE);752append(p_target);753}754755void GDScriptByteCodeGenerator::write_start_ternary(const Address &p_target) {756ternary_result.push_back(p_target);757}758759void GDScriptByteCodeGenerator::write_ternary_condition(const Address &p_condition) {760append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);761append(p_condition);762ternary_jump_fail_pos.push_back(opcodes.size());763append(0); // Jump target, will be patched.764}765766void GDScriptByteCodeGenerator::write_ternary_true_expr(const Address &p_expr) {767append_opcode(GDScriptFunction::OPCODE_ASSIGN);768append(ternary_result.back()->get());769append(p_expr);770// Jump away from the false path.771append_opcode(GDScriptFunction::OPCODE_JUMP);772ternary_jump_skip_pos.push_back(opcodes.size());773append(0);774// Fail must jump here.775patch_jump(ternary_jump_fail_pos.back()->get());776ternary_jump_fail_pos.pop_back();777}778779void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr) {780append_opcode(GDScriptFunction::OPCODE_ASSIGN);781append(ternary_result.back()->get());782append(p_expr);783}784785void GDScriptByteCodeGenerator::write_end_ternary() {786patch_jump(ternary_jump_skip_pos.back()->get());787ternary_jump_skip_pos.pop_back();788ternary_result.pop_back();789}790791void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) {792if (HAS_BUILTIN_TYPE(p_target)) {793if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type) &&794IS_BUILTIN_TYPE(p_source, Variant::get_indexed_element_type(p_target.type.builtin_type))) {795// Use indexed setter instead.796Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(p_target.type.builtin_type);797append_opcode(GDScriptFunction::OPCODE_SET_INDEXED_VALIDATED);798append(p_target);799append(p_index);800append(p_source);801append(setter);802return;803} else if (Variant::get_member_validated_keyed_setter(p_target.type.builtin_type)) {804Variant::ValidatedKeyedSetter setter = Variant::get_member_validated_keyed_setter(p_target.type.builtin_type);805append_opcode(GDScriptFunction::OPCODE_SET_KEYED_VALIDATED);806append(p_target);807append(p_index);808append(p_source);809append(setter);810return;811}812}813814append_opcode(GDScriptFunction::OPCODE_SET_KEYED);815append(p_target);816append(p_index);817append(p_source);818}819820void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address &p_index, const Address &p_source) {821if (HAS_BUILTIN_TYPE(p_source)) {822if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_getter(p_source.type.builtin_type)) {823// Use indexed getter instead.824Variant::ValidatedIndexedGetter getter = Variant::get_member_validated_indexed_getter(p_source.type.builtin_type);825append_opcode(GDScriptFunction::OPCODE_GET_INDEXED_VALIDATED);826append(p_source);827append(p_index);828append(p_target);829append(getter);830return;831} else if (Variant::get_member_validated_keyed_getter(p_source.type.builtin_type)) {832Variant::ValidatedKeyedGetter getter = Variant::get_member_validated_keyed_getter(p_source.type.builtin_type);833append_opcode(GDScriptFunction::OPCODE_GET_KEYED_VALIDATED);834append(p_source);835append(p_index);836append(p_target);837append(getter);838return;839}840}841append_opcode(GDScriptFunction::OPCODE_GET_KEYED);842append(p_source);843append(p_index);844append(p_target);845}846847void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) {848if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name) &&849IS_BUILTIN_TYPE(p_source, Variant::get_member_type(p_target.type.builtin_type, p_name))) {850Variant::ValidatedSetter setter = Variant::get_member_validated_setter(p_target.type.builtin_type, p_name);851append_opcode(GDScriptFunction::OPCODE_SET_NAMED_VALIDATED);852append(p_target);853append(p_source);854append(setter);855#ifdef DEBUG_ENABLED856add_debug_name(setter_names, get_setter_pos(setter), p_name);857#endif858return;859}860append_opcode(GDScriptFunction::OPCODE_SET_NAMED);861append(p_target);862append(p_source);863append(p_name);864}865866void GDScriptByteCodeGenerator::write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) {867if (HAS_BUILTIN_TYPE(p_source) && Variant::get_member_validated_getter(p_source.type.builtin_type, p_name)) {868Variant::ValidatedGetter getter = Variant::get_member_validated_getter(p_source.type.builtin_type, p_name);869append_opcode(GDScriptFunction::OPCODE_GET_NAMED_VALIDATED);870append(p_source);871append(p_target);872append(getter);873#ifdef DEBUG_ENABLED874add_debug_name(getter_names, get_getter_pos(getter), p_name);875#endif876return;877}878append_opcode(GDScriptFunction::OPCODE_GET_NAMED);879append(p_source);880append(p_target);881append(p_name);882}883884void GDScriptByteCodeGenerator::write_set_member(const Address &p_value, const StringName &p_name) {885append_opcode(GDScriptFunction::OPCODE_SET_MEMBER);886append(p_value);887append(p_name);888}889890void GDScriptByteCodeGenerator::write_get_member(const Address &p_target, const StringName &p_name) {891append_opcode(GDScriptFunction::OPCODE_GET_MEMBER);892append(p_target);893append(p_name);894}895896void GDScriptByteCodeGenerator::write_set_static_variable(const Address &p_value, const Address &p_class, int p_index) {897append_opcode(GDScriptFunction::OPCODE_SET_STATIC_VARIABLE);898append(p_value);899append(p_class);900append(p_index);901}902903void GDScriptByteCodeGenerator::write_get_static_variable(const Address &p_target, const Address &p_class, int p_index) {904append_opcode(GDScriptFunction::OPCODE_GET_STATIC_VARIABLE);905append(p_target);906append(p_class);907append(p_index);908}909910void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) {911switch (p_target.type.kind) {912case GDScriptDataType::BUILTIN: {913if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) {914const GDScriptDataType &element_type = p_target.type.get_container_element_type(0);915append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY);916append(p_target);917append(p_source);918append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));919append(element_type.builtin_type);920append(element_type.native_type);921} else if (p_target.type.builtin_type == Variant::DICTIONARY && p_target.type.has_container_element_types()) {922const GDScriptDataType &key_type = p_target.type.get_container_element_type_or_variant(0);923const GDScriptDataType &value_type = p_target.type.get_container_element_type_or_variant(1);924append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_DICTIONARY);925append(p_target);926append(p_source);927append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));928append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));929append(key_type.builtin_type);930append(key_type.native_type);931append(value_type.builtin_type);932append(value_type.native_type);933} else {934append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);935append(p_target);936append(p_source);937append(p_target.type.builtin_type);938}939} break;940case GDScriptDataType::NATIVE: {941int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];942Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];943class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);944append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE);945append(p_target);946append(p_source);947append(class_idx);948} break;949case GDScriptDataType::SCRIPT:950case GDScriptDataType::GDSCRIPT: {951Variant script = p_target.type.script_type;952int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);953954append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT);955append(p_target);956append(p_source);957append(idx);958} break;959default: {960ERR_PRINT("Compiler bug: unresolved assign.");961962// Shouldn't get here, but fail-safe to a regular assignment963append_opcode(GDScriptFunction::OPCODE_ASSIGN);964append(p_target);965append(p_source);966}967}968}969970void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) {971if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) {972const GDScriptDataType &element_type = p_target.type.get_container_element_type(0);973append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY);974append(p_target);975append(p_source);976append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));977append(element_type.builtin_type);978append(element_type.native_type);979} else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::DICTIONARY && p_target.type.has_container_element_types()) {980const GDScriptDataType &key_type = p_target.type.get_container_element_type_or_variant(0);981const GDScriptDataType &value_type = p_target.type.get_container_element_type_or_variant(1);982append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_DICTIONARY);983append(p_target);984append(p_source);985append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));986append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));987append(key_type.builtin_type);988append(key_type.native_type);989append(value_type.builtin_type);990append(value_type.native_type);991} else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {992// Need conversion.993append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);994append(p_target);995append(p_source);996append(p_target.type.builtin_type);997} else {998append_opcode(GDScriptFunction::OPCODE_ASSIGN);999append(p_target);1000append(p_source);1001}1002}10031004void GDScriptByteCodeGenerator::write_assign_null(const Address &p_target) {1005append_opcode(GDScriptFunction::OPCODE_ASSIGN_NULL);1006append(p_target);1007}10081009void GDScriptByteCodeGenerator::write_assign_true(const Address &p_target) {1010append_opcode(GDScriptFunction::OPCODE_ASSIGN_TRUE);1011append(p_target);1012}10131014void GDScriptByteCodeGenerator::write_assign_false(const Address &p_target) {1015append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);1016append(p_target);1017}10181019void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src, bool p_use_conversion) {1020if (p_use_conversion) {1021write_assign_with_conversion(p_dst, p_src);1022} else {1023write_assign(p_dst, p_src);1024}1025function->default_arguments.push_back(opcodes.size());1026}10271028void GDScriptByteCodeGenerator::write_store_global(const Address &p_dst, int p_global_index) {1029append_opcode(GDScriptFunction::OPCODE_STORE_GLOBAL);1030append(p_dst);1031append(p_global_index);1032}10331034void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) {1035append_opcode(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL);1036append(p_dst);1037append(p_global);1038}10391040void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {1041int index = 0;10421043switch (p_type.kind) {1044case GDScriptDataType::BUILTIN: {1045append_opcode(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);1046index = p_type.builtin_type;1047} break;1048case GDScriptDataType::NATIVE: {1049int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];1050Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];1051append_opcode(GDScriptFunction::OPCODE_CAST_TO_NATIVE);1052index = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);1053} break;1054case GDScriptDataType::SCRIPT:1055case GDScriptDataType::GDSCRIPT: {1056Variant script = p_type.script_type;1057int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);1058append_opcode(GDScriptFunction::OPCODE_CAST_TO_SCRIPT);1059index = idx;1060} break;1061default: {1062return;1063}1064}10651066append(p_source);1067append(p_target);1068append(index);1069}10701071GDScriptByteCodeGenerator::CallTarget GDScriptByteCodeGenerator::get_call_target(const GDScriptCodeGenerator::Address &p_target, Variant::Type p_type) {1072if (p_target.mode == Address::NIL) {1073GDScriptDataType type;1074if (p_type != Variant::NIL) {1075type.kind = GDScriptDataType::BUILTIN;1076type.builtin_type = p_type;1077}1078uint32_t addr = add_temporary(type);1079return CallTarget(Address(Address::TEMPORARY, addr, type), true, this);1080} else {1081return CallTarget(p_target, false, this);1082}1083}10841085void GDScriptByteCodeGenerator::write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1086append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1087for (int i = 0; i < p_arguments.size(); i++) {1088append(p_arguments[i]);1089}1090append(p_base);1091CallTarget ct = get_call_target(p_target);1092append(ct.target);1093append(p_arguments.size());1094append(p_function_name);1095ct.cleanup();1096}10971098void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1099append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_SELF_BASE, 1 + p_arguments.size());1100for (int i = 0; i < p_arguments.size(); i++) {1101append(p_arguments[i]);1102}1103CallTarget ct = get_call_target(p_target);1104append(ct.target);1105append(p_arguments.size());1106append(p_function_name);1107ct.cleanup();1108}11091110void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1111append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());1112for (int i = 0; i < p_arguments.size(); i++) {1113append(p_arguments[i]);1114}1115append(p_base);1116CallTarget ct = get_call_target(p_target);1117append(ct.target);1118append(p_arguments.size());1119append(p_function_name);1120ct.cleanup();1121}11221123void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {1124append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size());1125GDScriptUtilityFunctions::FunctionPtr gds_function = GDScriptUtilityFunctions::get_function(p_function);1126for (int i = 0; i < p_arguments.size(); i++) {1127append(p_arguments[i]);1128}1129CallTarget ct = get_call_target(p_target);1130append(ct.target);1131append(p_arguments.size());1132append(gds_function);1133ct.cleanup();1134#ifdef DEBUG_ENABLED1135add_debug_name(gds_utilities_names, get_gds_utility_pos(gds_function), p_function);1136#endif1137}11381139void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {1140bool is_validated = true;1141if (Variant::is_utility_function_vararg(p_function)) {1142is_validated = false; // Vararg needs runtime checks, can't use validated call.1143} else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) {1144bool all_types_exact = true;1145for (int i = 0; i < p_arguments.size(); i++) {1146if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_utility_function_argument_type(p_function, i))) {1147all_types_exact = false;1148break;1149}1150}11511152is_validated = all_types_exact;1153}11541155if (is_validated) {1156Variant::Type result_type = Variant::has_utility_function_return_value(p_function) ? Variant::get_utility_function_return_type(p_function) : Variant::NIL;1157CallTarget ct = get_call_target(p_target, result_type);1158Variant::Type temp_type = temporaries[ct.target.address].type;1159if (result_type != temp_type) {1160write_type_adjust(ct.target, result_type);1161}1162append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY_VALIDATED, 1 + p_arguments.size());1163for (int i = 0; i < p_arguments.size(); i++) {1164append(p_arguments[i]);1165}1166append(ct.target);1167append(p_arguments.size());1168append(Variant::get_validated_utility_function(p_function));1169ct.cleanup();1170#ifdef DEBUG_ENABLED1171add_debug_name(utilities_names, get_utility_pos(Variant::get_validated_utility_function(p_function)), p_function);1172#endif1173} else {1174append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size());1175for (int i = 0; i < p_arguments.size(); i++) {1176append(p_arguments[i]);1177}1178CallTarget ct = get_call_target(p_target);1179append(ct.target);1180append(p_arguments.size());1181append(p_function);1182ct.cleanup();1183}1184}11851186void GDScriptByteCodeGenerator::write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, bool p_is_static, const Vector<Address> &p_arguments) {1187bool is_validated = false;11881189// Check if all types are correct.1190if (Variant::is_builtin_method_vararg(p_type, p_method)) {1191is_validated = false; // Vararg needs runtime checks, can't use validated call.1192} else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) {1193bool all_types_exact = true;1194for (int i = 0; i < p_arguments.size(); i++) {1195if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) {1196all_types_exact = false;1197break;1198}1199}12001201is_validated = all_types_exact;1202}12031204if (!is_validated) {1205// Perform regular call.1206if (p_is_static) {1207append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_BUILTIN_STATIC, p_arguments.size() + 1);1208for (int i = 0; i < p_arguments.size(); i++) {1209append(p_arguments[i]);1210}1211CallTarget ct = get_call_target(p_target);1212append(ct.target);1213append(p_type);1214append(p_method);1215append(p_arguments.size());1216ct.cleanup();1217} else {1218write_call(p_target, p_base, p_method, p_arguments);1219}1220return;1221}12221223Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method);1224CallTarget ct = get_call_target(p_target, result_type);1225Variant::Type temp_type = temporaries[ct.target.address].type;1226if (result_type != temp_type) {1227write_type_adjust(ct.target, result_type);1228}12291230append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());12311232for (int i = 0; i < p_arguments.size(); i++) {1233append(p_arguments[i]);1234}1235append(p_base);1236append(ct.target);1237append(p_arguments.size());1238append(Variant::get_validated_builtin_method(p_type, p_method));1239ct.cleanup();12401241#ifdef DEBUG_ENABLED1242add_debug_name(builtin_methods_names, get_builtin_method_pos(Variant::get_validated_builtin_method(p_type, p_method)), p_method);1243#endif1244}12451246void 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) {1247write_call_builtin_type(p_target, p_base, p_type, p_method, false, p_arguments);1248}12491250void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) {1251write_call_builtin_type(p_target, Address(), p_type, p_method, true, p_arguments);1252}12531254void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) {1255MethodBind *method = ClassDB::get_method(p_class, p_method);12561257// Perform regular call.1258append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);1259for (int i = 0; i < p_arguments.size(); i++) {1260append(p_arguments[i]);1261}1262CallTarget ct = get_call_target(p_target);1263append(ct.target);1264append(method);1265append(p_arguments.size());1266ct.cleanup();1267return;1268}12691270void GDScriptByteCodeGenerator::write_call_native_static_validated(const GDScriptCodeGenerator::Address &p_target, MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {1271Variant::Type return_type = Variant::NIL;1272bool has_return = p_method->has_return();12731274if (has_return) {1275PropertyInfo return_info = p_method->get_return_info();1276return_type = return_info.type;1277}12781279CallTarget ct = get_call_target(p_target, return_type);12801281if (has_return) {1282Variant::Type temp_type = temporaries[ct.target.address].type;1283if (temp_type != return_type) {1284write_type_adjust(ct.target, return_type);1285}1286}12871288GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN;1289append_opcode_and_argcount(code, 1 + p_arguments.size());12901291for (int i = 0; i < p_arguments.size(); i++) {1292append(p_arguments[i]);1293}1294append(ct.target);1295append(p_arguments.size());1296append(p_method);1297ct.cleanup();1298}12991300void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {1301append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());1302for (int i = 0; i < p_arguments.size(); i++) {1303append(p_arguments[i]);1304}1305CallTarget ct = get_call_target(p_target);1306append(p_base);1307append(ct.target);1308append(p_arguments.size());1309append(p_method);1310ct.cleanup();1311}13121313void GDScriptByteCodeGenerator::write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {1314Variant::Type return_type = Variant::NIL;1315bool has_return = p_method->has_return();13161317if (has_return) {1318PropertyInfo return_info = p_method->get_return_info();1319return_type = return_info.type;1320}13211322CallTarget ct = get_call_target(p_target, return_type);13231324if (has_return) {1325Variant::Type temp_type = temporaries[ct.target.address].type;1326if (temp_type != return_type) {1327write_type_adjust(ct.target, return_type);1328}1329}13301331GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN;1332append_opcode_and_argcount(code, 2 + p_arguments.size());13331334for (int i = 0; i < p_arguments.size(); i++) {1335append(p_arguments[i]);1336}1337append(p_base);1338append(ct.target);1339append(p_arguments.size());1340append(p_method);1341ct.cleanup();1342}13431344void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1345append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1346for (int i = 0; i < p_arguments.size(); i++) {1347append(p_arguments[i]);1348}1349append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);1350CallTarget ct = get_call_target(p_target);1351append(ct.target);1352append(p_arguments.size());1353append(p_function_name);1354ct.cleanup();1355}13561357void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1358append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());1359for (int i = 0; i < p_arguments.size(); i++) {1360append(p_arguments[i]);1361}1362append(GDScriptFunction::ADDR_SELF);1363CallTarget ct = get_call_target(p_target);1364append(ct.target);1365append(p_arguments.size());1366append(p_function_name);1367ct.cleanup();1368}13691370void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1371append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1372for (int i = 0; i < p_arguments.size(); i++) {1373append(p_arguments[i]);1374}1375append(p_base);1376CallTarget ct = get_call_target(p_target);1377append(ct.target);1378append(p_arguments.size());1379append(p_function_name);1380ct.cleanup();1381}13821383void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) {1384append_opcode_and_argcount(p_use_self ? GDScriptFunction::OPCODE_CREATE_SELF_LAMBDA : GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());1385for (int i = 0; i < p_captures.size(); i++) {1386append(p_captures[i]);1387}13881389CallTarget ct = get_call_target(p_target);1390append(ct.target);1391append(p_captures.size());1392append(p_function);1393ct.cleanup();1394}13951396void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {1397// Try to find an appropriate constructor.1398bool all_have_type = true;1399Vector<Variant::Type> arg_types;1400for (int i = 0; i < p_arguments.size(); i++) {1401if (!HAS_BUILTIN_TYPE(p_arguments[i])) {1402all_have_type = false;1403break;1404}1405arg_types.push_back(p_arguments[i].type.builtin_type);1406}1407if (all_have_type) {1408int valid_constructor = -1;1409for (int i = 0; i < Variant::get_constructor_count(p_type); i++) {1410if (Variant::get_constructor_argument_count(p_type, i) != p_arguments.size()) {1411continue;1412}1413int types_correct = true;1414for (int j = 0; j < arg_types.size(); j++) {1415if (arg_types[j] != Variant::get_constructor_argument_type(p_type, i, j)) {1416types_correct = false;1417break;1418}1419}1420if (types_correct) {1421valid_constructor = i;1422break;1423}1424}1425if (valid_constructor >= 0) {1426append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_VALIDATED, 1 + p_arguments.size());1427for (int i = 0; i < p_arguments.size(); i++) {1428append(p_arguments[i]);1429}1430CallTarget ct = get_call_target(p_target);1431append(ct.target);1432append(p_arguments.size());1433append(Variant::get_validated_constructor(p_type, valid_constructor));1434ct.cleanup();1435#ifdef DEBUG_ENABLED1436add_debug_name(constructors_names, get_constructor_pos(Variant::get_validated_constructor(p_type, valid_constructor)), Variant::get_type_name(p_type));1437#endif1438return;1439}1440}14411442append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT, 1 + p_arguments.size());1443for (int i = 0; i < p_arguments.size(); i++) {1444append(p_arguments[i]);1445}1446CallTarget ct = get_call_target(p_target);1447append(ct.target);1448append(p_arguments.size());1449append(p_type);1450ct.cleanup();1451}14521453void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) {1454append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY, 1 + p_arguments.size());1455for (int i = 0; i < p_arguments.size(); i++) {1456append(p_arguments[i]);1457}1458CallTarget ct = get_call_target(p_target);1459append(ct.target);1460append(p_arguments.size());1461ct.cleanup();1462}14631464void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) {1465append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_ARRAY, 2 + p_arguments.size());1466for (int i = 0; i < p_arguments.size(); i++) {1467append(p_arguments[i]);1468}1469CallTarget ct = get_call_target(p_target);1470append(ct.target);1471append(get_constant_pos(p_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1472append(p_arguments.size());1473append(p_element_type.builtin_type);1474append(p_element_type.native_type);1475ct.cleanup();1476}14771478void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) {1479append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY, 1 + p_arguments.size());1480for (int i = 0; i < p_arguments.size(); i++) {1481append(p_arguments[i]);1482}1483CallTarget ct = get_call_target(p_target);1484append(ct.target);1485append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.1486ct.cleanup();1487}14881489void GDScriptByteCodeGenerator::write_construct_typed_dictionary(const Address &p_target, const GDScriptDataType &p_key_type, const GDScriptDataType &p_value_type, const Vector<Address> &p_arguments) {1490append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_DICTIONARY, 3 + p_arguments.size());1491for (int i = 0; i < p_arguments.size(); i++) {1492append(p_arguments[i]);1493}1494CallTarget ct = get_call_target(p_target);1495append(ct.target);1496append(get_constant_pos(p_key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1497append(get_constant_pos(p_value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1498append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.1499append(p_key_type.builtin_type);1500append(p_key_type.native_type);1501append(p_value_type.builtin_type);1502append(p_value_type.native_type);1503ct.cleanup();1504}15051506void GDScriptByteCodeGenerator::write_await(const Address &p_target, const Address &p_operand) {1507append_opcode(GDScriptFunction::OPCODE_AWAIT);1508append(p_operand);1509append_opcode(GDScriptFunction::OPCODE_AWAIT_RESUME);1510append(p_target);1511}15121513void GDScriptByteCodeGenerator::write_if(const Address &p_condition) {1514append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);1515append(p_condition);1516if_jmp_addrs.push_back(opcodes.size());1517append(0); // Jump destination, will be patched.1518}15191520void GDScriptByteCodeGenerator::write_else() {1521append_opcode(GDScriptFunction::OPCODE_JUMP); // Jump from true if block;1522int else_jmp_addr = opcodes.size();1523append(0); // Jump destination, will be patched.15241525patch_jump(if_jmp_addrs.back()->get());1526if_jmp_addrs.pop_back();1527if_jmp_addrs.push_back(else_jmp_addr);1528}15291530void GDScriptByteCodeGenerator::write_endif() {1531patch_jump(if_jmp_addrs.back()->get());1532if_jmp_addrs.pop_back();1533}15341535void GDScriptByteCodeGenerator::write_jump_if_shared(const Address &p_value) {1536append_opcode(GDScriptFunction::OPCODE_JUMP_IF_SHARED);1537append(p_value);1538if_jmp_addrs.push_back(opcodes.size());1539append(0); // Jump destination, will be patched.1540}15411542void GDScriptByteCodeGenerator::write_end_jump_if_shared() {1543patch_jump(if_jmp_addrs.back()->get());1544if_jmp_addrs.pop_back();1545}15461547void GDScriptByteCodeGenerator::start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type, bool p_is_range) {1548Address counter(Address::LOCAL_VARIABLE, add_local("@counter_pos", p_iterator_type), p_iterator_type);15491550// Store state.1551for_counter_variables.push_back(counter);15521553if (p_is_range) {1554GDScriptDataType int_type;1555int_type.kind = GDScriptDataType::BUILTIN;1556int_type.builtin_type = Variant::INT;15571558Address range_from(Address::LOCAL_VARIABLE, add_local("@range_from", int_type), int_type);1559Address range_to(Address::LOCAL_VARIABLE, add_local("@range_to", int_type), int_type);1560Address range_step(Address::LOCAL_VARIABLE, add_local("@range_step", int_type), int_type);15611562// Store state.1563for_range_from_variables.push_back(range_from);1564for_range_to_variables.push_back(range_to);1565for_range_step_variables.push_back(range_step);1566} else {1567Address container(Address::LOCAL_VARIABLE, add_local("@container_pos", p_list_type), p_list_type);15681569// Store state.1570for_container_variables.push_back(container);1571}1572}15731574void GDScriptByteCodeGenerator::write_for_list_assignment(const Address &p_list) {1575const Address &container = for_container_variables.back()->get();15761577// Assign container.1578append_opcode(GDScriptFunction::OPCODE_ASSIGN);1579append(container);1580append(p_list);1581}15821583void GDScriptByteCodeGenerator::write_for_range_assignment(const Address &p_from, const Address &p_to, const Address &p_step) {1584const Address &range_from = for_range_from_variables.back()->get();1585const Address &range_to = for_range_to_variables.back()->get();1586const Address &range_step = for_range_step_variables.back()->get();15871588// Assign range args.1589if (range_from.type == p_from.type) {1590write_assign(range_from, p_from);1591} else {1592write_assign_with_conversion(range_from, p_from);1593}1594if (range_to.type == p_to.type) {1595write_assign(range_to, p_to);1596} else {1597write_assign_with_conversion(range_to, p_to);1598}1599if (range_step.type == p_step.type) {1600write_assign(range_step, p_step);1601} else {1602write_assign_with_conversion(range_step, p_step);1603}1604}16051606void GDScriptByteCodeGenerator::write_for(const Address &p_variable, bool p_use_conversion, bool p_is_range) {1607const Address &counter = for_counter_variables.back()->get();1608const Address &container = p_is_range ? Address() : for_container_variables.back()->get();1609const Address &range_from = p_is_range ? for_range_from_variables.back()->get() : Address();1610const Address &range_to = p_is_range ? for_range_to_variables.back()->get() : Address();1611const Address &range_step = p_is_range ? for_range_step_variables.back()->get() : Address();16121613current_breaks_to_patch.push_back(List<int>());16141615GDScriptFunction::Opcode begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN;1616GDScriptFunction::Opcode iterate_opcode = GDScriptFunction::OPCODE_ITERATE;16171618if (p_is_range) {1619begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_RANGE;1620iterate_opcode = GDScriptFunction::OPCODE_ITERATE_RANGE;1621} else if (container.type.has_type()) {1622if (container.type.kind == GDScriptDataType::BUILTIN) {1623switch (container.type.builtin_type) {1624case Variant::INT:1625begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_INT;1626iterate_opcode = GDScriptFunction::OPCODE_ITERATE_INT;1627break;1628case Variant::FLOAT:1629begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_FLOAT;1630iterate_opcode = GDScriptFunction::OPCODE_ITERATE_FLOAT;1631break;1632case Variant::VECTOR2:1633begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2;1634iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2;1635break;1636case Variant::VECTOR2I:1637begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2I;1638iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2I;1639break;1640case Variant::VECTOR3:1641begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3;1642iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3;1643break;1644case Variant::VECTOR3I:1645begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3I;1646iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3I;1647break;1648case Variant::STRING:1649begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_STRING;1650iterate_opcode = GDScriptFunction::OPCODE_ITERATE_STRING;1651break;1652case Variant::DICTIONARY:1653begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_DICTIONARY;1654iterate_opcode = GDScriptFunction::OPCODE_ITERATE_DICTIONARY;1655break;1656case Variant::ARRAY:1657begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_ARRAY;1658iterate_opcode = GDScriptFunction::OPCODE_ITERATE_ARRAY;1659break;1660case Variant::PACKED_BYTE_ARRAY:1661begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY;1662iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_BYTE_ARRAY;1663break;1664case Variant::PACKED_INT32_ARRAY:1665begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY;1666iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT32_ARRAY;1667break;1668case Variant::PACKED_INT64_ARRAY:1669begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY;1670iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT64_ARRAY;1671break;1672case Variant::PACKED_FLOAT32_ARRAY:1673begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY;1674iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT32_ARRAY;1675break;1676case Variant::PACKED_FLOAT64_ARRAY:1677begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY;1678iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT64_ARRAY;1679break;1680case Variant::PACKED_STRING_ARRAY:1681begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY;1682iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_STRING_ARRAY;1683break;1684case Variant::PACKED_VECTOR2_ARRAY:1685begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY;1686iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR2_ARRAY;1687break;1688case Variant::PACKED_VECTOR3_ARRAY:1689begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY;1690iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR3_ARRAY;1691break;1692case Variant::PACKED_COLOR_ARRAY:1693begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY;1694iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_COLOR_ARRAY;1695break;1696case Variant::PACKED_VECTOR4_ARRAY:1697begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY;1698iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR4_ARRAY;1699break;1700default:1701break;1702}1703} else {1704begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_OBJECT;1705iterate_opcode = GDScriptFunction::OPCODE_ITERATE_OBJECT;1706}1707}17081709Address temp;1710if (p_use_conversion) {1711temp = Address(Address::LOCAL_VARIABLE, add_local("@iterator_temp", GDScriptDataType()));1712}17131714// Begin loop.1715append_opcode(begin_opcode);1716append(counter);1717if (p_is_range) {1718append(range_from);1719append(range_to);1720append(range_step);1721} else {1722append(container);1723}1724append(p_use_conversion ? temp : p_variable);1725for_jmp_addrs.push_back(opcodes.size());1726append(0); // End of loop address, will be patched.1727append_opcode(GDScriptFunction::OPCODE_JUMP);1728append(opcodes.size() + (p_is_range ? 7 : 6)); // Skip over 'continue' code.17291730// Next iteration.1731int continue_addr = opcodes.size();1732continue_addrs.push_back(continue_addr);1733append_opcode(iterate_opcode);1734append(counter);1735if (p_is_range) {1736append(range_to);1737append(range_step);1738} else {1739append(container);1740}1741append(p_use_conversion ? temp : p_variable);1742for_jmp_addrs.push_back(opcodes.size());1743append(0); // Jump destination, will be patched.17441745if (p_use_conversion) {1746write_assign_with_conversion(p_variable, temp);1747if (p_variable.type.can_contain_object()) {1748clear_address(temp); // Can contain `RefCounted`, so clear it.1749}1750}1751}17521753void GDScriptByteCodeGenerator::write_endfor(bool p_is_range) {1754// Jump back to loop check.1755append_opcode(GDScriptFunction::OPCODE_JUMP);1756append(continue_addrs.back()->get());1757continue_addrs.pop_back();17581759// Patch end jumps (two of them).1760for (int i = 0; i < 2; i++) {1761patch_jump(for_jmp_addrs.back()->get());1762for_jmp_addrs.pop_back();1763}17641765// Patch break statements.1766for (const int &E : current_breaks_to_patch.back()->get()) {1767patch_jump(E);1768}1769current_breaks_to_patch.pop_back();17701771// Pop state.1772for_counter_variables.pop_back();1773if (p_is_range) {1774for_range_from_variables.pop_back();1775for_range_to_variables.pop_back();1776for_range_step_variables.pop_back();1777} else {1778for_container_variables.pop_back();1779}1780}17811782void GDScriptByteCodeGenerator::start_while_condition() {1783current_breaks_to_patch.push_back(List<int>());1784continue_addrs.push_back(opcodes.size());1785}17861787void GDScriptByteCodeGenerator::write_while(const Address &p_condition) {1788// Condition check.1789append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);1790append(p_condition);1791while_jmp_addrs.push_back(opcodes.size());1792append(0); // End of loop address, will be patched.1793}17941795void GDScriptByteCodeGenerator::write_endwhile() {1796// Jump back to loop check.1797append_opcode(GDScriptFunction::OPCODE_JUMP);1798append(continue_addrs.back()->get());1799continue_addrs.pop_back();18001801// Patch end jump.1802patch_jump(while_jmp_addrs.back()->get());1803while_jmp_addrs.pop_back();18041805// Patch break statements.1806for (const int &E : current_breaks_to_patch.back()->get()) {1807patch_jump(E);1808}1809current_breaks_to_patch.pop_back();1810}18111812void GDScriptByteCodeGenerator::write_break() {1813append_opcode(GDScriptFunction::OPCODE_JUMP);1814current_breaks_to_patch.back()->get().push_back(opcodes.size());1815append(0);1816}18171818void GDScriptByteCodeGenerator::write_continue() {1819append_opcode(GDScriptFunction::OPCODE_JUMP);1820append(continue_addrs.back()->get());1821}18221823void GDScriptByteCodeGenerator::write_breakpoint() {1824append_opcode(GDScriptFunction::OPCODE_BREAKPOINT);1825}18261827void GDScriptByteCodeGenerator::write_newline(int p_line) {1828if (GDScriptLanguage::get_singleton()->should_track_call_stack()) {1829// Add newline for debugger and stack tracking if enabled in the project settings.1830append_opcode(GDScriptFunction::OPCODE_LINE);1831append(p_line);1832current_line = p_line;1833}1834}18351836void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {1837if (!function->return_type.has_type() || p_return_value.type.has_type()) {1838// Either the function is untyped or the return value is also typed.18391840// If this is a typed function, then we need to check for potential conversions.1841if (function->return_type.has_type()) {1842if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {1843// Typed array.1844const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);1845append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);1846append(p_return_value);1847append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1848append(element_type.builtin_type);1849append(element_type.native_type);1850} else if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::DICTIONARY &&1851function->return_type.has_container_element_types()) {1852// Typed dictionary.1853const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);1854const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);1855append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);1856append(p_return_value);1857append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1858append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1859append(key_type.builtin_type);1860append(key_type.native_type);1861append(value_type.builtin_type);1862append(value_type.native_type);1863} 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) {1864// Add conversion.1865append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);1866append(p_return_value);1867append(function->return_type.builtin_type);1868} else {1869// Just assign.1870append_opcode(GDScriptFunction::OPCODE_RETURN);1871append(p_return_value);1872}1873} else {1874append_opcode(GDScriptFunction::OPCODE_RETURN);1875append(p_return_value);1876}1877} else {1878switch (function->return_type.kind) {1879case GDScriptDataType::BUILTIN: {1880if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {1881const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);1882append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);1883append(p_return_value);1884append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1885append(element_type.builtin_type);1886append(element_type.native_type);1887} else if (function->return_type.builtin_type == Variant::DICTIONARY && function->return_type.has_container_element_types()) {1888const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);1889const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);1890append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);1891append(p_return_value);1892append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1893append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1894append(key_type.builtin_type);1895append(key_type.native_type);1896append(value_type.builtin_type);1897append(value_type.native_type);1898} else {1899append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);1900append(p_return_value);1901append(function->return_type.builtin_type);1902}1903} break;1904case GDScriptDataType::NATIVE: {1905append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE);1906append(p_return_value);1907int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];1908Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];1909class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);1910append(class_idx);1911} break;1912case GDScriptDataType::GDSCRIPT:1913case GDScriptDataType::SCRIPT: {1914Variant script = function->return_type.script_type;1915int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);19161917append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT);1918append(p_return_value);1919append(script_idx);1920} break;1921default: {1922ERR_PRINT("Compiler bug: unresolved return.");19231924// Shouldn't get here, but fail-safe to a regular return;1925append_opcode(GDScriptFunction::OPCODE_RETURN);1926append(p_return_value);1927} break;1928}1929}1930}19311932void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {1933append_opcode(GDScriptFunction::OPCODE_ASSERT);1934append(p_test);1935append(p_message);1936}19371938void GDScriptByteCodeGenerator::start_block() {1939push_stack_identifiers();1940}19411942void GDScriptByteCodeGenerator::end_block() {1943pop_stack_identifiers();1944}19451946void GDScriptByteCodeGenerator::clear_temporaries() {1947for (int slot_idx : temporaries_pending_clear) {1948// The temporary may have been reused as something else since it was added to the list.1949// In that case, there's **no** need to clear it.1950if (temporaries[slot_idx].can_contain_object) {1951clear_address(Address(Address::TEMPORARY, slot_idx)); // Can contain `RefCounted`, so clear it.1952}1953}1954temporaries_pending_clear.clear();1955}19561957void GDScriptByteCodeGenerator::clear_address(const Address &p_address) {1958// Do not check `is_local_dirty()` here! Always clear the address since the codegen doesn't track the compiler.1959// Also, this method is used to initialize local variables of built-in types, since they cannot be `null`.19601961if (p_address.type.kind == GDScriptDataType::BUILTIN) {1962switch (p_address.type.builtin_type) {1963case Variant::BOOL:1964write_assign_false(p_address);1965break;1966case Variant::DICTIONARY:1967if (p_address.type.has_container_element_types()) {1968write_construct_typed_dictionary(p_address, p_address.type.get_container_element_type_or_variant(0), p_address.type.get_container_element_type_or_variant(1), Vector<GDScriptCodeGenerator::Address>());1969} else {1970write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1971}1972break;1973case Variant::ARRAY:1974if (p_address.type.has_container_element_type(0)) {1975write_construct_typed_array(p_address, p_address.type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());1976} else {1977write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1978}1979break;1980case Variant::NIL:1981case Variant::OBJECT:1982write_assign_null(p_address);1983break;1984default:1985write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1986break;1987}1988} else {1989write_assign_null(p_address);1990}19911992if (p_address.mode == Address::LOCAL_VARIABLE) {1993dirty_locals.erase(p_address.address);1994}1995}19961997// Returns `true` if the local has been reused and not cleaned up with `clear_address()`.1998bool GDScriptByteCodeGenerator::is_local_dirty(const Address &p_address) const {1999ERR_FAIL_COND_V(p_address.mode != Address::LOCAL_VARIABLE, false);2000return dirty_locals.has(p_address.address);2001}20022003GDScriptByteCodeGenerator::~GDScriptByteCodeGenerator() {2004if (!ended && function != nullptr) {2005memdelete(function);2006}2007}200820092010