Path: blob/master/modules/gdscript/gdscript_byte_codegen.cpp
10278 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.has_type && 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}202} else {203function->_constants_ptr = nullptr;204function->_constant_count = 0;205}206207if (name_map.size()) {208function->global_names.resize(name_map.size());209function->_global_names_ptr = &function->global_names[0];210for (const KeyValue<StringName, int> &E : name_map) {211function->global_names.write[E.value] = E.key;212}213function->_global_names_count = function->global_names.size();214215} else {216function->_global_names_ptr = nullptr;217function->_global_names_count = 0;218}219220if (opcodes.size()) {221function->code = opcodes;222function->_code_ptr = &function->code.write[0];223function->_code_size = opcodes.size();224225} else {226function->_code_ptr = nullptr;227function->_code_size = 0;228}229230if (function->default_arguments.size()) {231function->_default_arg_count = function->default_arguments.size() - 1;232function->_default_arg_ptr = &function->default_arguments[0];233} else {234function->_default_arg_count = 0;235function->_default_arg_ptr = nullptr;236}237238if (operator_func_map.size()) {239function->operator_funcs.resize(operator_func_map.size());240function->_operator_funcs_count = function->operator_funcs.size();241function->_operator_funcs_ptr = function->operator_funcs.ptr();242for (const KeyValue<Variant::ValidatedOperatorEvaluator, int> &E : operator_func_map) {243function->operator_funcs.write[E.value] = E.key;244}245} else {246function->_operator_funcs_count = 0;247function->_operator_funcs_ptr = nullptr;248}249250if (setters_map.size()) {251function->setters.resize(setters_map.size());252function->_setters_count = function->setters.size();253function->_setters_ptr = function->setters.ptr();254for (const KeyValue<Variant::ValidatedSetter, int> &E : setters_map) {255function->setters.write[E.value] = E.key;256}257} else {258function->_setters_count = 0;259function->_setters_ptr = nullptr;260}261262if (getters_map.size()) {263function->getters.resize(getters_map.size());264function->_getters_count = function->getters.size();265function->_getters_ptr = function->getters.ptr();266for (const KeyValue<Variant::ValidatedGetter, int> &E : getters_map) {267function->getters.write[E.value] = E.key;268}269} else {270function->_getters_count = 0;271function->_getters_ptr = nullptr;272}273274if (keyed_setters_map.size()) {275function->keyed_setters.resize(keyed_setters_map.size());276function->_keyed_setters_count = function->keyed_setters.size();277function->_keyed_setters_ptr = function->keyed_setters.ptr();278for (const KeyValue<Variant::ValidatedKeyedSetter, int> &E : keyed_setters_map) {279function->keyed_setters.write[E.value] = E.key;280}281} else {282function->_keyed_setters_count = 0;283function->_keyed_setters_ptr = nullptr;284}285286if (keyed_getters_map.size()) {287function->keyed_getters.resize(keyed_getters_map.size());288function->_keyed_getters_count = function->keyed_getters.size();289function->_keyed_getters_ptr = function->keyed_getters.ptr();290for (const KeyValue<Variant::ValidatedKeyedGetter, int> &E : keyed_getters_map) {291function->keyed_getters.write[E.value] = E.key;292}293} else {294function->_keyed_getters_count = 0;295function->_keyed_getters_ptr = nullptr;296}297298if (indexed_setters_map.size()) {299function->indexed_setters.resize(indexed_setters_map.size());300function->_indexed_setters_count = function->indexed_setters.size();301function->_indexed_setters_ptr = function->indexed_setters.ptr();302for (const KeyValue<Variant::ValidatedIndexedSetter, int> &E : indexed_setters_map) {303function->indexed_setters.write[E.value] = E.key;304}305} else {306function->_indexed_setters_count = 0;307function->_indexed_setters_ptr = nullptr;308}309310if (indexed_getters_map.size()) {311function->indexed_getters.resize(indexed_getters_map.size());312function->_indexed_getters_count = function->indexed_getters.size();313function->_indexed_getters_ptr = function->indexed_getters.ptr();314for (const KeyValue<Variant::ValidatedIndexedGetter, int> &E : indexed_getters_map) {315function->indexed_getters.write[E.value] = E.key;316}317} else {318function->_indexed_getters_count = 0;319function->_indexed_getters_ptr = nullptr;320}321322if (builtin_method_map.size()) {323function->builtin_methods.resize(builtin_method_map.size());324function->_builtin_methods_ptr = function->builtin_methods.ptr();325function->_builtin_methods_count = builtin_method_map.size();326for (const KeyValue<Variant::ValidatedBuiltInMethod, int> &E : builtin_method_map) {327function->builtin_methods.write[E.value] = E.key;328}329} else {330function->_builtin_methods_ptr = nullptr;331function->_builtin_methods_count = 0;332}333334if (constructors_map.size()) {335function->constructors.resize(constructors_map.size());336function->_constructors_ptr = function->constructors.ptr();337function->_constructors_count = constructors_map.size();338for (const KeyValue<Variant::ValidatedConstructor, int> &E : constructors_map) {339function->constructors.write[E.value] = E.key;340}341} else {342function->_constructors_ptr = nullptr;343function->_constructors_count = 0;344}345346if (utilities_map.size()) {347function->utilities.resize(utilities_map.size());348function->_utilities_ptr = function->utilities.ptr();349function->_utilities_count = utilities_map.size();350for (const KeyValue<Variant::ValidatedUtilityFunction, int> &E : utilities_map) {351function->utilities.write[E.value] = E.key;352}353} else {354function->_utilities_ptr = nullptr;355function->_utilities_count = 0;356}357358if (gds_utilities_map.size()) {359function->gds_utilities.resize(gds_utilities_map.size());360function->_gds_utilities_ptr = function->gds_utilities.ptr();361function->_gds_utilities_count = gds_utilities_map.size();362for (const KeyValue<GDScriptUtilityFunctions::FunctionPtr, int> &E : gds_utilities_map) {363function->gds_utilities.write[E.value] = E.key;364}365} else {366function->_gds_utilities_ptr = nullptr;367function->_gds_utilities_count = 0;368}369370if (method_bind_map.size()) {371function->methods.resize(method_bind_map.size());372function->_methods_ptr = function->methods.ptrw();373function->_methods_count = method_bind_map.size();374for (const KeyValue<MethodBind *, int> &E : method_bind_map) {375function->methods.write[E.value] = E.key;376}377} else {378function->_methods_ptr = nullptr;379function->_methods_count = 0;380}381382if (lambdas_map.size()) {383function->lambdas.resize(lambdas_map.size());384function->_lambdas_ptr = function->lambdas.ptrw();385function->_lambdas_count = lambdas_map.size();386for (const KeyValue<GDScriptFunction *, int> &E : lambdas_map) {387function->lambdas.write[E.value] = E.key;388}389} else {390function->_lambdas_ptr = nullptr;391function->_lambdas_count = 0;392}393394if (GDScriptLanguage::get_singleton()->should_track_locals()) {395function->stack_debug = stack_debug;396}397function->_stack_size = GDScriptFunction::FIXED_ADDRESSES_MAX + max_locals + temporaries.size();398function->_instruction_args_size = instr_args_max;399400#ifdef DEBUG_ENABLED401function->operator_names = operator_names;402function->setter_names = setter_names;403function->getter_names = getter_names;404function->builtin_methods_names = builtin_methods_names;405function->constructors_names = constructors_names;406function->utilities_names = utilities_names;407function->gds_utilities_names = gds_utilities_names;408#endif409410ended = true;411return function;412}413414#ifdef DEBUG_ENABLED415void GDScriptByteCodeGenerator::set_signature(const String &p_signature) {416function->profile.signature = p_signature;417}418#endif419420void GDScriptByteCodeGenerator::set_initial_line(int p_line) {421function->_initial_line = p_line;422}423424#define HAS_BUILTIN_TYPE(m_var) \425(m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN)426427#define IS_BUILTIN_TYPE(m_var, m_type) \428(m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type && m_type != Variant::NIL)429430void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Variant::Type p_new_type) {431switch (p_new_type) {432case Variant::BOOL:433append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_BOOL);434break;435case Variant::INT:436append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_INT);437break;438case Variant::FLOAT:439append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_FLOAT);440break;441case Variant::STRING:442append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING);443break;444case Variant::VECTOR2:445append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2);446break;447case Variant::VECTOR2I:448append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR2I);449break;450case Variant::RECT2:451append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2);452break;453case Variant::RECT2I:454append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_RECT2I);455break;456case Variant::VECTOR3:457append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3);458break;459case Variant::VECTOR3I:460append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3I);461break;462case Variant::TRANSFORM2D:463append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM2D);464break;465case Variant::VECTOR4:466append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3);467break;468case Variant::VECTOR4I:469append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_VECTOR3I);470break;471case Variant::PLANE:472append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PLANE);473break;474case Variant::QUATERNION:475append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_QUATERNION);476break;477case Variant::AABB:478append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_AABB);479break;480case Variant::BASIS:481append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS);482break;483case Variant::TRANSFORM3D:484append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM3D);485break;486case Variant::PROJECTION:487append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PROJECTION);488break;489case Variant::COLOR:490append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR);491break;492case Variant::STRING_NAME:493append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_STRING_NAME);494break;495case Variant::NODE_PATH:496append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_NODE_PATH);497break;498case Variant::RID:499append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_RID);500break;501case Variant::OBJECT:502append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_OBJECT);503break;504case Variant::CALLABLE:505append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_CALLABLE);506break;507case Variant::SIGNAL:508append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_SIGNAL);509break;510case Variant::DICTIONARY:511append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_DICTIONARY);512break;513case Variant::ARRAY:514append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_ARRAY);515break;516case Variant::PACKED_BYTE_ARRAY:517append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY);518break;519case Variant::PACKED_INT32_ARRAY:520append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY);521break;522case Variant::PACKED_INT64_ARRAY:523append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY);524break;525case Variant::PACKED_FLOAT32_ARRAY:526append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY);527break;528case Variant::PACKED_FLOAT64_ARRAY:529append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY);530break;531case Variant::PACKED_STRING_ARRAY:532append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY);533break;534case Variant::PACKED_VECTOR2_ARRAY:535append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY);536break;537case Variant::PACKED_VECTOR3_ARRAY:538append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY);539break;540case Variant::PACKED_COLOR_ARRAY:541append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY);542break;543case Variant::PACKED_VECTOR4_ARRAY:544append_opcode(GDScriptFunction::OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY);545break;546case Variant::NIL:547case Variant::VARIANT_MAX:548return;549}550append(p_target);551}552553void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand) {554if (HAS_BUILTIN_TYPE(p_left_operand)) {555// Gather specific operator.556Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, Variant::NIL);557558append_opcode(GDScriptFunction::OPCODE_OPERATOR_VALIDATED);559append(p_left_operand);560append(Address());561append(p_target);562append(op_func);563#ifdef DEBUG_ENABLED564add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator));565#endif566return;567}568569// No specific types, perform variant evaluation.570append_opcode(GDScriptFunction::OPCODE_OPERATOR);571append(p_left_operand);572append(Address());573append(p_target);574append(p_operator);575append(0); // Signature storage.576append(0); // Return type storage.577constexpr int _pointer_size = sizeof(Variant::ValidatedOperatorEvaluator) / sizeof(*(opcodes.ptr()));578for (int i = 0; i < _pointer_size; i++) {579append(0); // Space for function pointer.580}581}582583void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {584bool valid = HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand);585586// Avoid validated evaluator for modulo and division when operands are int or integer vector, since there's no check for division by zero.587if (valid && (p_operator == Variant::OP_DIVIDE || p_operator == Variant::OP_MODULE)) {588switch (p_left_operand.type.builtin_type) {589case Variant::INT:590// Cannot use modulo between int / float, we should raise an error later in GDScript591valid = p_right_operand.type.builtin_type != Variant::INT && p_operator == Variant::OP_DIVIDE;592break;593case Variant::VECTOR2I:594case Variant::VECTOR3I:595case Variant::VECTOR4I:596valid = p_right_operand.type.builtin_type != Variant::INT && p_right_operand.type.builtin_type != p_left_operand.type.builtin_type;597break;598default:599break;600}601}602603if (valid) {604if (p_target.mode == Address::TEMPORARY) {605Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);606Variant::Type temp_type = temporaries[p_target.address].type;607if (result_type != temp_type) {608write_type_adjust(p_target, result_type);609}610}611612// Gather specific operator.613Variant::ValidatedOperatorEvaluator op_func = Variant::get_validated_operator_evaluator(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);614615append_opcode(GDScriptFunction::OPCODE_OPERATOR_VALIDATED);616append(p_left_operand);617append(p_right_operand);618append(p_target);619append(op_func);620#ifdef DEBUG_ENABLED621add_debug_name(operator_names, get_operation_pos(op_func), Variant::get_operator_name(p_operator));622#endif623return;624}625626// No specific types, perform variant evaluation.627append_opcode(GDScriptFunction::OPCODE_OPERATOR);628append(p_left_operand);629append(p_right_operand);630append(p_target);631append(p_operator);632append(0); // Signature storage.633append(0); // Return type storage.634constexpr int _pointer_size = sizeof(Variant::ValidatedOperatorEvaluator) / sizeof(*(opcodes.ptr()));635for (int i = 0; i < _pointer_size; i++) {636append(0); // Space for function pointer.637}638}639640void GDScriptByteCodeGenerator::write_type_test(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {641switch (p_type.kind) {642case GDScriptDataType::BUILTIN: {643if (p_type.builtin_type == Variant::ARRAY && p_type.has_container_element_type(0)) {644const GDScriptDataType &element_type = p_type.get_container_element_type(0);645append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_ARRAY);646append(p_target);647append(p_source);648append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));649append(element_type.builtin_type);650append(element_type.native_type);651} else if (p_type.builtin_type == Variant::DICTIONARY && p_type.has_container_element_types()) {652const GDScriptDataType &key_element_type = p_type.get_container_element_type_or_variant(0);653const GDScriptDataType &value_element_type = p_type.get_container_element_type_or_variant(1);654append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_DICTIONARY);655append(p_target);656append(p_source);657append(get_constant_pos(key_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));658append(get_constant_pos(value_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));659append(key_element_type.builtin_type);660append(key_element_type.native_type);661append(value_element_type.builtin_type);662append(value_element_type.native_type);663} else {664append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_BUILTIN);665append(p_target);666append(p_source);667append(p_type.builtin_type);668}669} break;670case GDScriptDataType::NATIVE: {671append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_NATIVE);672append(p_target);673append(p_source);674append(p_type.native_type);675} break;676case GDScriptDataType::SCRIPT:677case GDScriptDataType::GDSCRIPT: {678const Variant &script = p_type.script_type;679append_opcode(GDScriptFunction::OPCODE_TYPE_TEST_SCRIPT);680append(p_target);681append(p_source);682append(get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));683} break;684default: {685ERR_PRINT("Compiler bug: unresolved type in type test.");686append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);687append(p_target);688}689}690}691692void GDScriptByteCodeGenerator::write_and_left_operand(const Address &p_left_operand) {693append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);694append(p_left_operand);695logic_op_jump_pos1.push_back(opcodes.size());696append(0); // Jump target, will be patched.697}698699void GDScriptByteCodeGenerator::write_and_right_operand(const Address &p_right_operand) {700append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);701append(p_right_operand);702logic_op_jump_pos2.push_back(opcodes.size());703append(0); // Jump target, will be patched.704}705706void GDScriptByteCodeGenerator::write_end_and(const Address &p_target) {707// If here means both operands are true.708append_opcode(GDScriptFunction::OPCODE_ASSIGN_TRUE);709append(p_target);710// Jump away from the fail condition.711append_opcode(GDScriptFunction::OPCODE_JUMP);712append(opcodes.size() + 3);713// Here it means one of operands is false.714patch_jump(logic_op_jump_pos1.back()->get());715patch_jump(logic_op_jump_pos2.back()->get());716logic_op_jump_pos1.pop_back();717logic_op_jump_pos2.pop_back();718append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);719append(p_target);720}721722void GDScriptByteCodeGenerator::write_or_left_operand(const Address &p_left_operand) {723append_opcode(GDScriptFunction::OPCODE_JUMP_IF);724append(p_left_operand);725logic_op_jump_pos1.push_back(opcodes.size());726append(0); // Jump target, will be patched.727}728729void GDScriptByteCodeGenerator::write_or_right_operand(const Address &p_right_operand) {730append_opcode(GDScriptFunction::OPCODE_JUMP_IF);731append(p_right_operand);732logic_op_jump_pos2.push_back(opcodes.size());733append(0); // Jump target, will be patched.734}735736void GDScriptByteCodeGenerator::write_end_or(const Address &p_target) {737// If here means both operands are false.738append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);739append(p_target);740// Jump away from the success condition.741append_opcode(GDScriptFunction::OPCODE_JUMP);742append(opcodes.size() + 3);743// Here it means one of operands is true.744patch_jump(logic_op_jump_pos1.back()->get());745patch_jump(logic_op_jump_pos2.back()->get());746logic_op_jump_pos1.pop_back();747logic_op_jump_pos2.pop_back();748append_opcode(GDScriptFunction::OPCODE_ASSIGN_TRUE);749append(p_target);750}751752void GDScriptByteCodeGenerator::write_start_ternary(const Address &p_target) {753ternary_result.push_back(p_target);754}755756void GDScriptByteCodeGenerator::write_ternary_condition(const Address &p_condition) {757append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);758append(p_condition);759ternary_jump_fail_pos.push_back(opcodes.size());760append(0); // Jump target, will be patched.761}762763void GDScriptByteCodeGenerator::write_ternary_true_expr(const Address &p_expr) {764append_opcode(GDScriptFunction::OPCODE_ASSIGN);765append(ternary_result.back()->get());766append(p_expr);767// Jump away from the false path.768append_opcode(GDScriptFunction::OPCODE_JUMP);769ternary_jump_skip_pos.push_back(opcodes.size());770append(0);771// Fail must jump here.772patch_jump(ternary_jump_fail_pos.back()->get());773ternary_jump_fail_pos.pop_back();774}775776void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr) {777append_opcode(GDScriptFunction::OPCODE_ASSIGN);778append(ternary_result.back()->get());779append(p_expr);780}781782void GDScriptByteCodeGenerator::write_end_ternary() {783patch_jump(ternary_jump_skip_pos.back()->get());784ternary_jump_skip_pos.pop_back();785ternary_result.pop_back();786}787788void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) {789if (HAS_BUILTIN_TYPE(p_target)) {790if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type) &&791IS_BUILTIN_TYPE(p_source, Variant::get_indexed_element_type(p_target.type.builtin_type))) {792// Use indexed setter instead.793Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(p_target.type.builtin_type);794append_opcode(GDScriptFunction::OPCODE_SET_INDEXED_VALIDATED);795append(p_target);796append(p_index);797append(p_source);798append(setter);799return;800} else if (Variant::get_member_validated_keyed_setter(p_target.type.builtin_type)) {801Variant::ValidatedKeyedSetter setter = Variant::get_member_validated_keyed_setter(p_target.type.builtin_type);802append_opcode(GDScriptFunction::OPCODE_SET_KEYED_VALIDATED);803append(p_target);804append(p_index);805append(p_source);806append(setter);807return;808}809}810811append_opcode(GDScriptFunction::OPCODE_SET_KEYED);812append(p_target);813append(p_index);814append(p_source);815}816817void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address &p_index, const Address &p_source) {818if (HAS_BUILTIN_TYPE(p_source)) {819if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_getter(p_source.type.builtin_type)) {820// Use indexed getter instead.821Variant::ValidatedIndexedGetter getter = Variant::get_member_validated_indexed_getter(p_source.type.builtin_type);822append_opcode(GDScriptFunction::OPCODE_GET_INDEXED_VALIDATED);823append(p_source);824append(p_index);825append(p_target);826append(getter);827return;828} else if (Variant::get_member_validated_keyed_getter(p_source.type.builtin_type)) {829Variant::ValidatedKeyedGetter getter = Variant::get_member_validated_keyed_getter(p_source.type.builtin_type);830append_opcode(GDScriptFunction::OPCODE_GET_KEYED_VALIDATED);831append(p_source);832append(p_index);833append(p_target);834append(getter);835return;836}837}838append_opcode(GDScriptFunction::OPCODE_GET_KEYED);839append(p_source);840append(p_index);841append(p_target);842}843844void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) {845if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name) &&846IS_BUILTIN_TYPE(p_source, Variant::get_member_type(p_target.type.builtin_type, p_name))) {847Variant::ValidatedSetter setter = Variant::get_member_validated_setter(p_target.type.builtin_type, p_name);848append_opcode(GDScriptFunction::OPCODE_SET_NAMED_VALIDATED);849append(p_target);850append(p_source);851append(setter);852#ifdef DEBUG_ENABLED853add_debug_name(setter_names, get_setter_pos(setter), p_name);854#endif855return;856}857append_opcode(GDScriptFunction::OPCODE_SET_NAMED);858append(p_target);859append(p_source);860append(p_name);861}862863void GDScriptByteCodeGenerator::write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) {864if (HAS_BUILTIN_TYPE(p_source) && Variant::get_member_validated_getter(p_source.type.builtin_type, p_name)) {865Variant::ValidatedGetter getter = Variant::get_member_validated_getter(p_source.type.builtin_type, p_name);866append_opcode(GDScriptFunction::OPCODE_GET_NAMED_VALIDATED);867append(p_source);868append(p_target);869append(getter);870#ifdef DEBUG_ENABLED871add_debug_name(getter_names, get_getter_pos(getter), p_name);872#endif873return;874}875append_opcode(GDScriptFunction::OPCODE_GET_NAMED);876append(p_source);877append(p_target);878append(p_name);879}880881void GDScriptByteCodeGenerator::write_set_member(const Address &p_value, const StringName &p_name) {882append_opcode(GDScriptFunction::OPCODE_SET_MEMBER);883append(p_value);884append(p_name);885}886887void GDScriptByteCodeGenerator::write_get_member(const Address &p_target, const StringName &p_name) {888append_opcode(GDScriptFunction::OPCODE_GET_MEMBER);889append(p_target);890append(p_name);891}892893void GDScriptByteCodeGenerator::write_set_static_variable(const Address &p_value, const Address &p_class, int p_index) {894append_opcode(GDScriptFunction::OPCODE_SET_STATIC_VARIABLE);895append(p_value);896append(p_class);897append(p_index);898}899900void GDScriptByteCodeGenerator::write_get_static_variable(const Address &p_target, const Address &p_class, int p_index) {901append_opcode(GDScriptFunction::OPCODE_GET_STATIC_VARIABLE);902append(p_target);903append(p_class);904append(p_index);905}906907void GDScriptByteCodeGenerator::write_assign_with_conversion(const Address &p_target, const Address &p_source) {908switch (p_target.type.kind) {909case GDScriptDataType::BUILTIN: {910if (p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) {911const GDScriptDataType &element_type = p_target.type.get_container_element_type(0);912append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY);913append(p_target);914append(p_source);915append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));916append(element_type.builtin_type);917append(element_type.native_type);918} else if (p_target.type.builtin_type == Variant::DICTIONARY && p_target.type.has_container_element_types()) {919const GDScriptDataType &key_type = p_target.type.get_container_element_type_or_variant(0);920const GDScriptDataType &value_type = p_target.type.get_container_element_type_or_variant(1);921append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_DICTIONARY);922append(p_target);923append(p_source);924append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));925append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));926append(key_type.builtin_type);927append(key_type.native_type);928append(value_type.builtin_type);929append(value_type.native_type);930} else {931append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);932append(p_target);933append(p_source);934append(p_target.type.builtin_type);935}936} break;937case GDScriptDataType::NATIVE: {938int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_target.type.native_type];939Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];940class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);941append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_NATIVE);942append(p_target);943append(p_source);944append(class_idx);945} break;946case GDScriptDataType::SCRIPT:947case GDScriptDataType::GDSCRIPT: {948Variant script = p_target.type.script_type;949int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);950951append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_SCRIPT);952append(p_target);953append(p_source);954append(idx);955} break;956default: {957ERR_PRINT("Compiler bug: unresolved assign.");958959// Shouldn't get here, but fail-safe to a regular assignment960append_opcode(GDScriptFunction::OPCODE_ASSIGN);961append(p_target);962append(p_source);963}964}965}966967void GDScriptByteCodeGenerator::write_assign(const Address &p_target, const Address &p_source) {968if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::ARRAY && p_target.type.has_container_element_type(0)) {969const GDScriptDataType &element_type = p_target.type.get_container_element_type(0);970append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_ARRAY);971append(p_target);972append(p_source);973append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));974append(element_type.builtin_type);975append(element_type.native_type);976} else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type == Variant::DICTIONARY && p_target.type.has_container_element_types()) {977const GDScriptDataType &key_type = p_target.type.get_container_element_type_or_variant(0);978const GDScriptDataType &value_type = p_target.type.get_container_element_type_or_variant(1);979append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_DICTIONARY);980append(p_target);981append(p_source);982append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));983append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));984append(key_type.builtin_type);985append(key_type.native_type);986append(value_type.builtin_type);987append(value_type.native_type);988} else if (p_target.type.kind == GDScriptDataType::BUILTIN && p_source.type.kind == GDScriptDataType::BUILTIN && p_target.type.builtin_type != p_source.type.builtin_type) {989// Need conversion.990append_opcode(GDScriptFunction::OPCODE_ASSIGN_TYPED_BUILTIN);991append(p_target);992append(p_source);993append(p_target.type.builtin_type);994} else {995append_opcode(GDScriptFunction::OPCODE_ASSIGN);996append(p_target);997append(p_source);998}999}10001001void GDScriptByteCodeGenerator::write_assign_null(const Address &p_target) {1002append_opcode(GDScriptFunction::OPCODE_ASSIGN_NULL);1003append(p_target);1004}10051006void GDScriptByteCodeGenerator::write_assign_true(const Address &p_target) {1007append_opcode(GDScriptFunction::OPCODE_ASSIGN_TRUE);1008append(p_target);1009}10101011void GDScriptByteCodeGenerator::write_assign_false(const Address &p_target) {1012append_opcode(GDScriptFunction::OPCODE_ASSIGN_FALSE);1013append(p_target);1014}10151016void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_dst, const Address &p_src, bool p_use_conversion) {1017if (p_use_conversion) {1018write_assign_with_conversion(p_dst, p_src);1019} else {1020write_assign(p_dst, p_src);1021}1022function->default_arguments.push_back(opcodes.size());1023}10241025void GDScriptByteCodeGenerator::write_store_global(const Address &p_dst, int p_global_index) {1026append_opcode(GDScriptFunction::OPCODE_STORE_GLOBAL);1027append(p_dst);1028append(p_global_index);1029}10301031void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) {1032append_opcode(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL);1033append(p_dst);1034append(p_global);1035}10361037void GDScriptByteCodeGenerator::write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) {1038int index = 0;10391040switch (p_type.kind) {1041case GDScriptDataType::BUILTIN: {1042append_opcode(GDScriptFunction::OPCODE_CAST_TO_BUILTIN);1043index = p_type.builtin_type;1044} break;1045case GDScriptDataType::NATIVE: {1046int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[p_type.native_type];1047Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];1048append_opcode(GDScriptFunction::OPCODE_CAST_TO_NATIVE);1049index = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);1050} break;1051case GDScriptDataType::SCRIPT:1052case GDScriptDataType::GDSCRIPT: {1053Variant script = p_type.script_type;1054int idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);1055append_opcode(GDScriptFunction::OPCODE_CAST_TO_SCRIPT);1056index = idx;1057} break;1058default: {1059return;1060}1061}10621063append(p_source);1064append(p_target);1065append(index);1066}10671068GDScriptByteCodeGenerator::CallTarget GDScriptByteCodeGenerator::get_call_target(const GDScriptCodeGenerator::Address &p_target, Variant::Type p_type) {1069if (p_target.mode == Address::NIL) {1070GDScriptDataType type;1071if (p_type != Variant::NIL) {1072type.has_type = true;1073type.kind = GDScriptDataType::BUILTIN;1074type.builtin_type = p_type;1075}1076uint32_t addr = add_temporary(type);1077return CallTarget(Address(Address::TEMPORARY, addr, type), true, this);1078} else {1079return CallTarget(p_target, false, this);1080}1081}10821083void GDScriptByteCodeGenerator::write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1084append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1085for (int i = 0; i < p_arguments.size(); i++) {1086append(p_arguments[i]);1087}1088append(p_base);1089CallTarget ct = get_call_target(p_target);1090append(ct.target);1091append(p_arguments.size());1092append(p_function_name);1093ct.cleanup();1094}10951096void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1097append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_SELF_BASE, 1 + p_arguments.size());1098for (int i = 0; i < p_arguments.size(); i++) {1099append(p_arguments[i]);1100}1101CallTarget ct = get_call_target(p_target);1102append(ct.target);1103append(p_arguments.size());1104append(p_function_name);1105ct.cleanup();1106}11071108void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1109append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());1110for (int i = 0; i < p_arguments.size(); i++) {1111append(p_arguments[i]);1112}1113append(p_base);1114CallTarget ct = get_call_target(p_target);1115append(ct.target);1116append(p_arguments.size());1117append(p_function_name);1118ct.cleanup();1119}11201121void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {1122append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size());1123GDScriptUtilityFunctions::FunctionPtr gds_function = GDScriptUtilityFunctions::get_function(p_function);1124for (int i = 0; i < p_arguments.size(); i++) {1125append(p_arguments[i]);1126}1127CallTarget ct = get_call_target(p_target);1128append(ct.target);1129append(p_arguments.size());1130append(gds_function);1131ct.cleanup();1132#ifdef DEBUG_ENABLED1133add_debug_name(gds_utilities_names, get_gds_utility_pos(gds_function), p_function);1134#endif1135}11361137void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {1138bool is_validated = true;1139if (Variant::is_utility_function_vararg(p_function)) {1140is_validated = false; // Vararg needs runtime checks, can't use validated call.1141} else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) {1142bool all_types_exact = true;1143for (int i = 0; i < p_arguments.size(); i++) {1144if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_utility_function_argument_type(p_function, i))) {1145all_types_exact = false;1146break;1147}1148}11491150is_validated = all_types_exact;1151}11521153if (is_validated) {1154Variant::Type result_type = Variant::has_utility_function_return_value(p_function) ? Variant::get_utility_function_return_type(p_function) : Variant::NIL;1155CallTarget ct = get_call_target(p_target, result_type);1156Variant::Type temp_type = temporaries[ct.target.address].type;1157if (result_type != temp_type) {1158write_type_adjust(ct.target, result_type);1159}1160append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY_VALIDATED, 1 + p_arguments.size());1161for (int i = 0; i < p_arguments.size(); i++) {1162append(p_arguments[i]);1163}1164append(ct.target);1165append(p_arguments.size());1166append(Variant::get_validated_utility_function(p_function));1167ct.cleanup();1168#ifdef DEBUG_ENABLED1169add_debug_name(utilities_names, get_utility_pos(Variant::get_validated_utility_function(p_function)), p_function);1170#endif1171} else {1172append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size());1173for (int i = 0; i < p_arguments.size(); i++) {1174append(p_arguments[i]);1175}1176CallTarget ct = get_call_target(p_target);1177append(ct.target);1178append(p_arguments.size());1179append(p_function);1180ct.cleanup();1181}1182}11831184void 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) {1185bool is_validated = false;11861187// Check if all types are correct.1188if (Variant::is_builtin_method_vararg(p_type, p_method)) {1189is_validated = false; // Vararg needs runtime checks, can't use validated call.1190} else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) {1191bool all_types_exact = true;1192for (int i = 0; i < p_arguments.size(); i++) {1193if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) {1194all_types_exact = false;1195break;1196}1197}11981199is_validated = all_types_exact;1200}12011202if (!is_validated) {1203// Perform regular call.1204if (p_is_static) {1205append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_BUILTIN_STATIC, p_arguments.size() + 1);1206for (int i = 0; i < p_arguments.size(); i++) {1207append(p_arguments[i]);1208}1209CallTarget ct = get_call_target(p_target);1210append(ct.target);1211append(p_type);1212append(p_method);1213append(p_arguments.size());1214ct.cleanup();1215} else {1216write_call(p_target, p_base, p_method, p_arguments);1217}1218return;1219}12201221Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method);1222CallTarget ct = get_call_target(p_target, result_type);1223Variant::Type temp_type = temporaries[ct.target.address].type;1224if (result_type != temp_type) {1225write_type_adjust(ct.target, result_type);1226}12271228append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());12291230for (int i = 0; i < p_arguments.size(); i++) {1231append(p_arguments[i]);1232}1233append(p_base);1234append(ct.target);1235append(p_arguments.size());1236append(Variant::get_validated_builtin_method(p_type, p_method));1237ct.cleanup();12381239#ifdef DEBUG_ENABLED1240add_debug_name(builtin_methods_names, get_builtin_method_pos(Variant::get_validated_builtin_method(p_type, p_method)), p_method);1241#endif1242}12431244void 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) {1245write_call_builtin_type(p_target, p_base, p_type, p_method, false, p_arguments);1246}12471248void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) {1249write_call_builtin_type(p_target, Address(), p_type, p_method, true, p_arguments);1250}12511252void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) {1253MethodBind *method = ClassDB::get_method(p_class, p_method);12541255// Perform regular call.1256append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);1257for (int i = 0; i < p_arguments.size(); i++) {1258append(p_arguments[i]);1259}1260CallTarget ct = get_call_target(p_target);1261append(ct.target);1262append(method);1263append(p_arguments.size());1264ct.cleanup();1265return;1266}12671268void GDScriptByteCodeGenerator::write_call_native_static_validated(const GDScriptCodeGenerator::Address &p_target, MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {1269Variant::Type return_type = Variant::NIL;1270bool has_return = p_method->has_return();12711272if (has_return) {1273PropertyInfo return_info = p_method->get_return_info();1274return_type = return_info.type;1275}12761277CallTarget ct = get_call_target(p_target, return_type);12781279if (has_return) {1280Variant::Type temp_type = temporaries[ct.target.address].type;1281if (temp_type != return_type) {1282write_type_adjust(ct.target, return_type);1283}1284}12851286GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN;1287append_opcode_and_argcount(code, 1 + p_arguments.size());12881289for (int i = 0; i < p_arguments.size(); i++) {1290append(p_arguments[i]);1291}1292append(ct.target);1293append(p_arguments.size());1294append(p_method);1295ct.cleanup();1296}12971298void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {1299append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());1300for (int i = 0; i < p_arguments.size(); i++) {1301append(p_arguments[i]);1302}1303CallTarget ct = get_call_target(p_target);1304append(p_base);1305append(ct.target);1306append(p_arguments.size());1307append(p_method);1308ct.cleanup();1309}13101311void GDScriptByteCodeGenerator::write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {1312Variant::Type return_type = Variant::NIL;1313bool has_return = p_method->has_return();13141315if (has_return) {1316PropertyInfo return_info = p_method->get_return_info();1317return_type = return_info.type;1318}13191320CallTarget ct = get_call_target(p_target, return_type);13211322if (has_return) {1323Variant::Type temp_type = temporaries[ct.target.address].type;1324if (temp_type != return_type) {1325write_type_adjust(ct.target, return_type);1326}1327}13281329GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN;1330append_opcode_and_argcount(code, 2 + p_arguments.size());13311332for (int i = 0; i < p_arguments.size(); i++) {1333append(p_arguments[i]);1334}1335append(p_base);1336append(ct.target);1337append(p_arguments.size());1338append(p_method);1339ct.cleanup();1340}13411342void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1343append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1344for (int i = 0; i < p_arguments.size(); i++) {1345append(p_arguments[i]);1346}1347append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);1348CallTarget ct = get_call_target(p_target);1349append(ct.target);1350append(p_arguments.size());1351append(p_function_name);1352ct.cleanup();1353}13541355void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1356append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());1357for (int i = 0; i < p_arguments.size(); i++) {1358append(p_arguments[i]);1359}1360append(GDScriptFunction::ADDR_SELF);1361CallTarget ct = get_call_target(p_target);1362append(ct.target);1363append(p_arguments.size());1364append(p_function_name);1365ct.cleanup();1366}13671368void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1369append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1370for (int i = 0; i < p_arguments.size(); i++) {1371append(p_arguments[i]);1372}1373append(p_base);1374CallTarget ct = get_call_target(p_target);1375append(ct.target);1376append(p_arguments.size());1377append(p_function_name);1378ct.cleanup();1379}13801381void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) {1382append_opcode_and_argcount(p_use_self ? GDScriptFunction::OPCODE_CREATE_SELF_LAMBDA : GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());1383for (int i = 0; i < p_captures.size(); i++) {1384append(p_captures[i]);1385}13861387CallTarget ct = get_call_target(p_target);1388append(ct.target);1389append(p_captures.size());1390append(p_function);1391ct.cleanup();1392}13931394void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {1395// Try to find an appropriate constructor.1396bool all_have_type = true;1397Vector<Variant::Type> arg_types;1398for (int i = 0; i < p_arguments.size(); i++) {1399if (!HAS_BUILTIN_TYPE(p_arguments[i])) {1400all_have_type = false;1401break;1402}1403arg_types.push_back(p_arguments[i].type.builtin_type);1404}1405if (all_have_type) {1406int valid_constructor = -1;1407for (int i = 0; i < Variant::get_constructor_count(p_type); i++) {1408if (Variant::get_constructor_argument_count(p_type, i) != p_arguments.size()) {1409continue;1410}1411int types_correct = true;1412for (int j = 0; j < arg_types.size(); j++) {1413if (arg_types[j] != Variant::get_constructor_argument_type(p_type, i, j)) {1414types_correct = false;1415break;1416}1417}1418if (types_correct) {1419valid_constructor = i;1420break;1421}1422}1423if (valid_constructor >= 0) {1424append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_VALIDATED, 1 + p_arguments.size());1425for (int i = 0; i < p_arguments.size(); i++) {1426append(p_arguments[i]);1427}1428CallTarget ct = get_call_target(p_target);1429append(ct.target);1430append(p_arguments.size());1431append(Variant::get_validated_constructor(p_type, valid_constructor));1432ct.cleanup();1433#ifdef DEBUG_ENABLED1434add_debug_name(constructors_names, get_constructor_pos(Variant::get_validated_constructor(p_type, valid_constructor)), Variant::get_type_name(p_type));1435#endif1436return;1437}1438}14391440append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT, 1 + p_arguments.size());1441for (int i = 0; i < p_arguments.size(); i++) {1442append(p_arguments[i]);1443}1444CallTarget ct = get_call_target(p_target);1445append(ct.target);1446append(p_arguments.size());1447append(p_type);1448ct.cleanup();1449}14501451void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) {1452append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY, 1 + p_arguments.size());1453for (int i = 0; i < p_arguments.size(); i++) {1454append(p_arguments[i]);1455}1456CallTarget ct = get_call_target(p_target);1457append(ct.target);1458append(p_arguments.size());1459ct.cleanup();1460}14611462void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) {1463append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_ARRAY, 2 + p_arguments.size());1464for (int i = 0; i < p_arguments.size(); i++) {1465append(p_arguments[i]);1466}1467CallTarget ct = get_call_target(p_target);1468append(ct.target);1469append(get_constant_pos(p_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1470append(p_arguments.size());1471append(p_element_type.builtin_type);1472append(p_element_type.native_type);1473ct.cleanup();1474}14751476void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) {1477append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY, 1 + p_arguments.size());1478for (int i = 0; i < p_arguments.size(); i++) {1479append(p_arguments[i]);1480}1481CallTarget ct = get_call_target(p_target);1482append(ct.target);1483append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.1484ct.cleanup();1485}14861487void GDScriptByteCodeGenerator::write_construct_typed_dictionary(const Address &p_target, const GDScriptDataType &p_key_type, const GDScriptDataType &p_value_type, const Vector<Address> &p_arguments) {1488append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_DICTIONARY, 3 + p_arguments.size());1489for (int i = 0; i < p_arguments.size(); i++) {1490append(p_arguments[i]);1491}1492CallTarget ct = get_call_target(p_target);1493append(ct.target);1494append(get_constant_pos(p_key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1495append(get_constant_pos(p_value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1496append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.1497append(p_key_type.builtin_type);1498append(p_key_type.native_type);1499append(p_value_type.builtin_type);1500append(p_value_type.native_type);1501ct.cleanup();1502}15031504void GDScriptByteCodeGenerator::write_await(const Address &p_target, const Address &p_operand) {1505append_opcode(GDScriptFunction::OPCODE_AWAIT);1506append(p_operand);1507append_opcode(GDScriptFunction::OPCODE_AWAIT_RESUME);1508append(p_target);1509}15101511void GDScriptByteCodeGenerator::write_if(const Address &p_condition) {1512append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);1513append(p_condition);1514if_jmp_addrs.push_back(opcodes.size());1515append(0); // Jump destination, will be patched.1516}15171518void GDScriptByteCodeGenerator::write_else() {1519append_opcode(GDScriptFunction::OPCODE_JUMP); // Jump from true if block;1520int else_jmp_addr = opcodes.size();1521append(0); // Jump destination, will be patched.15221523patch_jump(if_jmp_addrs.back()->get());1524if_jmp_addrs.pop_back();1525if_jmp_addrs.push_back(else_jmp_addr);1526}15271528void GDScriptByteCodeGenerator::write_endif() {1529patch_jump(if_jmp_addrs.back()->get());1530if_jmp_addrs.pop_back();1531}15321533void GDScriptByteCodeGenerator::write_jump_if_shared(const Address &p_value) {1534append_opcode(GDScriptFunction::OPCODE_JUMP_IF_SHARED);1535append(p_value);1536if_jmp_addrs.push_back(opcodes.size());1537append(0); // Jump destination, will be patched.1538}15391540void GDScriptByteCodeGenerator::write_end_jump_if_shared() {1541patch_jump(if_jmp_addrs.back()->get());1542if_jmp_addrs.pop_back();1543}15441545void GDScriptByteCodeGenerator::start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type, bool p_is_range) {1546Address counter(Address::LOCAL_VARIABLE, add_local("@counter_pos", p_iterator_type), p_iterator_type);15471548// Store state.1549for_counter_variables.push_back(counter);15501551if (p_is_range) {1552GDScriptDataType int_type;1553int_type.has_type = true;1554int_type.kind = GDScriptDataType::BUILTIN;1555int_type.builtin_type = Variant::INT;15561557Address range_from(Address::LOCAL_VARIABLE, add_local("@range_from", int_type), int_type);1558Address range_to(Address::LOCAL_VARIABLE, add_local("@range_to", int_type), int_type);1559Address range_step(Address::LOCAL_VARIABLE, add_local("@range_step", int_type), int_type);15601561// Store state.1562for_range_from_variables.push_back(range_from);1563for_range_to_variables.push_back(range_to);1564for_range_step_variables.push_back(range_step);1565} else {1566Address container(Address::LOCAL_VARIABLE, add_local("@container_pos", p_list_type), p_list_type);15671568// Store state.1569for_container_variables.push_back(container);1570}1571}15721573void GDScriptByteCodeGenerator::write_for_list_assignment(const Address &p_list) {1574const Address &container = for_container_variables.back()->get();15751576// Assign container.1577append_opcode(GDScriptFunction::OPCODE_ASSIGN);1578append(container);1579append(p_list);1580}15811582void GDScriptByteCodeGenerator::write_for_range_assignment(const Address &p_from, const Address &p_to, const Address &p_step) {1583const Address &range_from = for_range_from_variables.back()->get();1584const Address &range_to = for_range_to_variables.back()->get();1585const Address &range_step = for_range_step_variables.back()->get();15861587// Assign range args.1588if (range_from.type == p_from.type) {1589write_assign(range_from, p_from);1590} else {1591write_assign_with_conversion(range_from, p_from);1592}1593if (range_to.type == p_to.type) {1594write_assign(range_to, p_to);1595} else {1596write_assign_with_conversion(range_to, p_to);1597}1598if (range_step.type == p_step.type) {1599write_assign(range_step, p_step);1600} else {1601write_assign_with_conversion(range_step, p_step);1602}1603}16041605void GDScriptByteCodeGenerator::write_for(const Address &p_variable, bool p_use_conversion, bool p_is_range) {1606const Address &counter = for_counter_variables.back()->get();1607const Address &container = p_is_range ? Address() : for_container_variables.back()->get();1608const Address &range_from = p_is_range ? for_range_from_variables.back()->get() : Address();1609const Address &range_to = p_is_range ? for_range_to_variables.back()->get() : Address();1610const Address &range_step = p_is_range ? for_range_step_variables.back()->get() : Address();16111612current_breaks_to_patch.push_back(List<int>());16131614GDScriptFunction::Opcode begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN;1615GDScriptFunction::Opcode iterate_opcode = GDScriptFunction::OPCODE_ITERATE;16161617if (p_is_range) {1618begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_RANGE;1619iterate_opcode = GDScriptFunction::OPCODE_ITERATE_RANGE;1620} else if (container.type.has_type) {1621if (container.type.kind == GDScriptDataType::BUILTIN) {1622switch (container.type.builtin_type) {1623case Variant::INT:1624begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_INT;1625iterate_opcode = GDScriptFunction::OPCODE_ITERATE_INT;1626break;1627case Variant::FLOAT:1628begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_FLOAT;1629iterate_opcode = GDScriptFunction::OPCODE_ITERATE_FLOAT;1630break;1631case Variant::VECTOR2:1632begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2;1633iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2;1634break;1635case Variant::VECTOR2I:1636begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2I;1637iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2I;1638break;1639case Variant::VECTOR3:1640begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3;1641iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3;1642break;1643case Variant::VECTOR3I:1644begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3I;1645iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3I;1646break;1647case Variant::STRING:1648begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_STRING;1649iterate_opcode = GDScriptFunction::OPCODE_ITERATE_STRING;1650break;1651case Variant::DICTIONARY:1652begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_DICTIONARY;1653iterate_opcode = GDScriptFunction::OPCODE_ITERATE_DICTIONARY;1654break;1655case Variant::ARRAY:1656begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_ARRAY;1657iterate_opcode = GDScriptFunction::OPCODE_ITERATE_ARRAY;1658break;1659case Variant::PACKED_BYTE_ARRAY:1660begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY;1661iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_BYTE_ARRAY;1662break;1663case Variant::PACKED_INT32_ARRAY:1664begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY;1665iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT32_ARRAY;1666break;1667case Variant::PACKED_INT64_ARRAY:1668begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY;1669iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT64_ARRAY;1670break;1671case Variant::PACKED_FLOAT32_ARRAY:1672begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY;1673iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT32_ARRAY;1674break;1675case Variant::PACKED_FLOAT64_ARRAY:1676begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY;1677iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT64_ARRAY;1678break;1679case Variant::PACKED_STRING_ARRAY:1680begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY;1681iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_STRING_ARRAY;1682break;1683case Variant::PACKED_VECTOR2_ARRAY:1684begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY;1685iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR2_ARRAY;1686break;1687case Variant::PACKED_VECTOR3_ARRAY:1688begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY;1689iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR3_ARRAY;1690break;1691case Variant::PACKED_COLOR_ARRAY:1692begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY;1693iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_COLOR_ARRAY;1694break;1695case Variant::PACKED_VECTOR4_ARRAY:1696begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY;1697iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR4_ARRAY;1698break;1699default:1700break;1701}1702} else {1703begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_OBJECT;1704iterate_opcode = GDScriptFunction::OPCODE_ITERATE_OBJECT;1705}1706}17071708Address temp;1709if (p_use_conversion) {1710temp = Address(Address::LOCAL_VARIABLE, add_local("@iterator_temp", GDScriptDataType()));1711}17121713// Begin loop.1714append_opcode(begin_opcode);1715append(counter);1716if (p_is_range) {1717append(range_from);1718append(range_to);1719append(range_step);1720} else {1721append(container);1722}1723append(p_use_conversion ? temp : p_variable);1724for_jmp_addrs.push_back(opcodes.size());1725append(0); // End of loop address, will be patched.1726append_opcode(GDScriptFunction::OPCODE_JUMP);1727append(opcodes.size() + (p_is_range ? 7 : 6)); // Skip over 'continue' code.17281729// Next iteration.1730int continue_addr = opcodes.size();1731continue_addrs.push_back(continue_addr);1732append_opcode(iterate_opcode);1733append(counter);1734if (p_is_range) {1735append(range_to);1736append(range_step);1737} else {1738append(container);1739}1740append(p_use_conversion ? temp : p_variable);1741for_jmp_addrs.push_back(opcodes.size());1742append(0); // Jump destination, will be patched.17431744if (p_use_conversion) {1745write_assign_with_conversion(p_variable, temp);1746if (p_variable.type.can_contain_object()) {1747clear_address(temp); // Can contain `RefCounted`, so clear it.1748}1749}1750}17511752void GDScriptByteCodeGenerator::write_endfor(bool p_is_range) {1753// Jump back to loop check.1754append_opcode(GDScriptFunction::OPCODE_JUMP);1755append(continue_addrs.back()->get());1756continue_addrs.pop_back();17571758// Patch end jumps (two of them).1759for (int i = 0; i < 2; i++) {1760patch_jump(for_jmp_addrs.back()->get());1761for_jmp_addrs.pop_back();1762}17631764// Patch break statements.1765for (const int &E : current_breaks_to_patch.back()->get()) {1766patch_jump(E);1767}1768current_breaks_to_patch.pop_back();17691770// Pop state.1771for_counter_variables.pop_back();1772if (p_is_range) {1773for_range_from_variables.pop_back();1774for_range_to_variables.pop_back();1775for_range_step_variables.pop_back();1776} else {1777for_container_variables.pop_back();1778}1779}17801781void GDScriptByteCodeGenerator::start_while_condition() {1782current_breaks_to_patch.push_back(List<int>());1783continue_addrs.push_back(opcodes.size());1784}17851786void GDScriptByteCodeGenerator::write_while(const Address &p_condition) {1787// Condition check.1788append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);1789append(p_condition);1790while_jmp_addrs.push_back(opcodes.size());1791append(0); // End of loop address, will be patched.1792}17931794void GDScriptByteCodeGenerator::write_endwhile() {1795// Jump back to loop check.1796append_opcode(GDScriptFunction::OPCODE_JUMP);1797append(continue_addrs.back()->get());1798continue_addrs.pop_back();17991800// Patch end jump.1801patch_jump(while_jmp_addrs.back()->get());1802while_jmp_addrs.pop_back();18031804// Patch break statements.1805for (const int &E : current_breaks_to_patch.back()->get()) {1806patch_jump(E);1807}1808current_breaks_to_patch.pop_back();1809}18101811void GDScriptByteCodeGenerator::write_break() {1812append_opcode(GDScriptFunction::OPCODE_JUMP);1813current_breaks_to_patch.back()->get().push_back(opcodes.size());1814append(0);1815}18161817void GDScriptByteCodeGenerator::write_continue() {1818append_opcode(GDScriptFunction::OPCODE_JUMP);1819append(continue_addrs.back()->get());1820}18211822void GDScriptByteCodeGenerator::write_breakpoint() {1823append_opcode(GDScriptFunction::OPCODE_BREAKPOINT);1824}18251826void GDScriptByteCodeGenerator::write_newline(int p_line) {1827if (GDScriptLanguage::get_singleton()->should_track_call_stack()) {1828// Add newline for debugger and stack tracking if enabled in the project settings.1829append_opcode(GDScriptFunction::OPCODE_LINE);1830append(p_line);1831current_line = p_line;1832}1833}18341835void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {1836if (!function->return_type.has_type || p_return_value.type.has_type) {1837// Either the function is untyped or the return value is also typed.18381839// If this is a typed function, then we need to check for potential conversions.1840if (function->return_type.has_type) {1841if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {1842// Typed array.1843const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);1844append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);1845append(p_return_value);1846append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1847append(element_type.builtin_type);1848append(element_type.native_type);1849} else if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::DICTIONARY &&1850function->return_type.has_container_element_types()) {1851// Typed dictionary.1852const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);1853const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);1854append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);1855append(p_return_value);1856append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1857append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1858append(key_type.builtin_type);1859append(key_type.native_type);1860append(value_type.builtin_type);1861append(value_type.native_type);1862} 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) {1863// Add conversion.1864append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);1865append(p_return_value);1866append(function->return_type.builtin_type);1867} else {1868// Just assign.1869append_opcode(GDScriptFunction::OPCODE_RETURN);1870append(p_return_value);1871}1872} else {1873append_opcode(GDScriptFunction::OPCODE_RETURN);1874append(p_return_value);1875}1876} else {1877switch (function->return_type.kind) {1878case GDScriptDataType::BUILTIN: {1879if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {1880const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);1881append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);1882append(p_return_value);1883append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1884append(element_type.builtin_type);1885append(element_type.native_type);1886} else if (function->return_type.builtin_type == Variant::DICTIONARY && function->return_type.has_container_element_types()) {1887const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);1888const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);1889append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);1890append(p_return_value);1891append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1892append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1893append(key_type.builtin_type);1894append(key_type.native_type);1895append(value_type.builtin_type);1896append(value_type.native_type);1897} else {1898append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);1899append(p_return_value);1900append(function->return_type.builtin_type);1901}1902} break;1903case GDScriptDataType::NATIVE: {1904append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE);1905append(p_return_value);1906int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];1907Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];1908class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);1909append(class_idx);1910} break;1911case GDScriptDataType::GDSCRIPT:1912case GDScriptDataType::SCRIPT: {1913Variant script = function->return_type.script_type;1914int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);19151916append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT);1917append(p_return_value);1918append(script_idx);1919} break;1920default: {1921ERR_PRINT("Compiler bug: unresolved return.");19221923// Shouldn't get here, but fail-safe to a regular return;1924append_opcode(GDScriptFunction::OPCODE_RETURN);1925append(p_return_value);1926} break;1927}1928}1929}19301931void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {1932append_opcode(GDScriptFunction::OPCODE_ASSERT);1933append(p_test);1934append(p_message);1935}19361937void GDScriptByteCodeGenerator::start_block() {1938push_stack_identifiers();1939}19401941void GDScriptByteCodeGenerator::end_block() {1942pop_stack_identifiers();1943}19441945void GDScriptByteCodeGenerator::clear_temporaries() {1946for (int slot_idx : temporaries_pending_clear) {1947// The temporary may have been reused as something else since it was added to the list.1948// In that case, there's **no** need to clear it.1949if (temporaries[slot_idx].can_contain_object) {1950clear_address(Address(Address::TEMPORARY, slot_idx)); // Can contain `RefCounted`, so clear it.1951}1952}1953temporaries_pending_clear.clear();1954}19551956void GDScriptByteCodeGenerator::clear_address(const Address &p_address) {1957// Do not check `is_local_dirty()` here! Always clear the address since the codegen doesn't track the compiler.1958// Also, this method is used to initialize local variables of built-in types, since they cannot be `null`.19591960if (p_address.type.has_type && p_address.type.kind == GDScriptDataType::BUILTIN) {1961switch (p_address.type.builtin_type) {1962case Variant::BOOL:1963write_assign_false(p_address);1964break;1965case Variant::DICTIONARY:1966if (p_address.type.has_container_element_types()) {1967write_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>());1968} else {1969write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1970}1971break;1972case Variant::ARRAY:1973if (p_address.type.has_container_element_type(0)) {1974write_construct_typed_array(p_address, p_address.type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());1975} else {1976write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1977}1978break;1979case Variant::NIL:1980case Variant::OBJECT:1981write_assign_null(p_address);1982break;1983default:1984write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1985break;1986}1987} else {1988write_assign_null(p_address);1989}19901991if (p_address.mode == Address::LOCAL_VARIABLE) {1992dirty_locals.erase(p_address.address);1993}1994}19951996// Returns `true` if the local has been reused and not cleaned up with `clear_address()`.1997bool GDScriptByteCodeGenerator::is_local_dirty(const Address &p_address) const {1998ERR_FAIL_COND_V(p_address.mode != Address::LOCAL_VARIABLE, false);1999return dirty_locals.has(p_address.address);2000}20012002GDScriptByteCodeGenerator::~GDScriptByteCodeGenerator() {2003if (!ended && function != nullptr) {2004memdelete(function);2005}2006}200720082009