Path: blob/master/modules/gdscript/gdscript_byte_codegen.cpp
11351 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}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.kind == GDScriptDataType::BUILTIN)426427#define IS_BUILTIN_TYPE(m_var, m_type) \428(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.kind = GDScriptDataType::BUILTIN;1073type.builtin_type = p_type;1074}1075uint32_t addr = add_temporary(type);1076return CallTarget(Address(Address::TEMPORARY, addr, type), true, this);1077} else {1078return CallTarget(p_target, false, this);1079}1080}10811082void GDScriptByteCodeGenerator::write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1083append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1084for (int i = 0; i < p_arguments.size(); i++) {1085append(p_arguments[i]);1086}1087append(p_base);1088CallTarget ct = get_call_target(p_target);1089append(ct.target);1090append(p_arguments.size());1091append(p_function_name);1092ct.cleanup();1093}10941095void GDScriptByteCodeGenerator::write_super_call(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1096append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_SELF_BASE, 1 + p_arguments.size());1097for (int i = 0; i < p_arguments.size(); i++) {1098append(p_arguments[i]);1099}1100CallTarget ct = get_call_target(p_target);1101append(ct.target);1102append(p_arguments.size());1103append(p_function_name);1104ct.cleanup();1105}11061107void GDScriptByteCodeGenerator::write_call_async(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1108append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());1109for (int i = 0; i < p_arguments.size(); i++) {1110append(p_arguments[i]);1111}1112append(p_base);1113CallTarget ct = get_call_target(p_target);1114append(ct.target);1115append(p_arguments.size());1116append(p_function_name);1117ct.cleanup();1118}11191120void GDScriptByteCodeGenerator::write_call_gdscript_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {1121append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_GDSCRIPT_UTILITY, 1 + p_arguments.size());1122GDScriptUtilityFunctions::FunctionPtr gds_function = GDScriptUtilityFunctions::get_function(p_function);1123for (int i = 0; i < p_arguments.size(); i++) {1124append(p_arguments[i]);1125}1126CallTarget ct = get_call_target(p_target);1127append(ct.target);1128append(p_arguments.size());1129append(gds_function);1130ct.cleanup();1131#ifdef DEBUG_ENABLED1132add_debug_name(gds_utilities_names, get_gds_utility_pos(gds_function), p_function);1133#endif1134}11351136void GDScriptByteCodeGenerator::write_call_utility(const Address &p_target, const StringName &p_function, const Vector<Address> &p_arguments) {1137bool is_validated = true;1138if (Variant::is_utility_function_vararg(p_function)) {1139is_validated = false; // Vararg needs runtime checks, can't use validated call.1140} else if (p_arguments.size() == Variant::get_utility_function_argument_count(p_function)) {1141bool all_types_exact = true;1142for (int i = 0; i < p_arguments.size(); i++) {1143if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_utility_function_argument_type(p_function, i))) {1144all_types_exact = false;1145break;1146}1147}11481149is_validated = all_types_exact;1150}11511152if (is_validated) {1153Variant::Type result_type = Variant::has_utility_function_return_value(p_function) ? Variant::get_utility_function_return_type(p_function) : Variant::NIL;1154CallTarget ct = get_call_target(p_target, result_type);1155Variant::Type temp_type = temporaries[ct.target.address].type;1156if (result_type != temp_type) {1157write_type_adjust(ct.target, result_type);1158}1159append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY_VALIDATED, 1 + p_arguments.size());1160for (int i = 0; i < p_arguments.size(); i++) {1161append(p_arguments[i]);1162}1163append(ct.target);1164append(p_arguments.size());1165append(Variant::get_validated_utility_function(p_function));1166ct.cleanup();1167#ifdef DEBUG_ENABLED1168add_debug_name(utilities_names, get_utility_pos(Variant::get_validated_utility_function(p_function)), p_function);1169#endif1170} else {1171append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_UTILITY, 1 + p_arguments.size());1172for (int i = 0; i < p_arguments.size(); i++) {1173append(p_arguments[i]);1174}1175CallTarget ct = get_call_target(p_target);1176append(ct.target);1177append(p_arguments.size());1178append(p_function);1179ct.cleanup();1180}1181}11821183void 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) {1184bool is_validated = false;11851186// Check if all types are correct.1187if (Variant::is_builtin_method_vararg(p_type, p_method)) {1188is_validated = false; // Vararg needs runtime checks, can't use validated call.1189} else if (p_arguments.size() == Variant::get_builtin_method_argument_count(p_type, p_method)) {1190bool all_types_exact = true;1191for (int i = 0; i < p_arguments.size(); i++) {1192if (!IS_BUILTIN_TYPE(p_arguments[i], Variant::get_builtin_method_argument_type(p_type, p_method, i))) {1193all_types_exact = false;1194break;1195}1196}11971198is_validated = all_types_exact;1199}12001201if (!is_validated) {1202// Perform regular call.1203if (p_is_static) {1204append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_BUILTIN_STATIC, p_arguments.size() + 1);1205for (int i = 0; i < p_arguments.size(); i++) {1206append(p_arguments[i]);1207}1208CallTarget ct = get_call_target(p_target);1209append(ct.target);1210append(p_type);1211append(p_method);1212append(p_arguments.size());1213ct.cleanup();1214} else {1215write_call(p_target, p_base, p_method, p_arguments);1216}1217return;1218}12191220Variant::Type result_type = Variant::get_builtin_method_return_type(p_type, p_method);1221CallTarget ct = get_call_target(p_target, result_type);1222Variant::Type temp_type = temporaries[ct.target.address].type;1223if (result_type != temp_type) {1224write_type_adjust(ct.target, result_type);1225}12261227append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_BUILTIN_TYPE_VALIDATED, 2 + p_arguments.size());12281229for (int i = 0; i < p_arguments.size(); i++) {1230append(p_arguments[i]);1231}1232append(p_base);1233append(ct.target);1234append(p_arguments.size());1235append(Variant::get_validated_builtin_method(p_type, p_method));1236ct.cleanup();12371238#ifdef DEBUG_ENABLED1239add_debug_name(builtin_methods_names, get_builtin_method_pos(Variant::get_validated_builtin_method(p_type, p_method)), p_method);1240#endif1241}12421243void 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) {1244write_call_builtin_type(p_target, p_base, p_type, p_method, false, p_arguments);1245}12461247void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) {1248write_call_builtin_type(p_target, Address(), p_type, p_method, true, p_arguments);1249}12501251void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) {1252MethodBind *method = ClassDB::get_method(p_class, p_method);12531254// Perform regular call.1255append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);1256for (int i = 0; i < p_arguments.size(); i++) {1257append(p_arguments[i]);1258}1259CallTarget ct = get_call_target(p_target);1260append(ct.target);1261append(method);1262append(p_arguments.size());1263ct.cleanup();1264return;1265}12661267void GDScriptByteCodeGenerator::write_call_native_static_validated(const GDScriptCodeGenerator::Address &p_target, MethodBind *p_method, const Vector<GDScriptCodeGenerator::Address> &p_arguments) {1268Variant::Type return_type = Variant::NIL;1269bool has_return = p_method->has_return();12701271if (has_return) {1272PropertyInfo return_info = p_method->get_return_info();1273return_type = return_info.type;1274}12751276CallTarget ct = get_call_target(p_target, return_type);12771278if (has_return) {1279Variant::Type temp_type = temporaries[ct.target.address].type;1280if (temp_type != return_type) {1281write_type_adjust(ct.target, return_type);1282}1283}12841285GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN;1286append_opcode_and_argcount(code, 1 + p_arguments.size());12871288for (int i = 0; i < p_arguments.size(); i++) {1289append(p_arguments[i]);1290}1291append(ct.target);1292append(p_arguments.size());1293append(p_method);1294ct.cleanup();1295}12961297void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {1298append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());1299for (int i = 0; i < p_arguments.size(); i++) {1300append(p_arguments[i]);1301}1302CallTarget ct = get_call_target(p_target);1303append(p_base);1304append(ct.target);1305append(p_arguments.size());1306append(p_method);1307ct.cleanup();1308}13091310void GDScriptByteCodeGenerator::write_call_method_bind_validated(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {1311Variant::Type return_type = Variant::NIL;1312bool has_return = p_method->has_return();13131314if (has_return) {1315PropertyInfo return_info = p_method->get_return_info();1316return_type = return_info.type;1317}13181319CallTarget ct = get_call_target(p_target, return_type);13201321if (has_return) {1322Variant::Type temp_type = temporaries[ct.target.address].type;1323if (temp_type != return_type) {1324write_type_adjust(ct.target, return_type);1325}1326}13271328GDScriptFunction::Opcode code = p_method->has_return() ? GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN : GDScriptFunction::OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN;1329append_opcode_and_argcount(code, 2 + p_arguments.size());13301331for (int i = 0; i < p_arguments.size(); i++) {1332append(p_arguments[i]);1333}1334append(p_base);1335append(ct.target);1336append(p_arguments.size());1337append(p_method);1338ct.cleanup();1339}13401341void GDScriptByteCodeGenerator::write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1342append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1343for (int i = 0; i < p_arguments.size(); i++) {1344append(p_arguments[i]);1345}1346append(GDScriptFunction::ADDR_TYPE_STACK << GDScriptFunction::ADDR_BITS);1347CallTarget ct = get_call_target(p_target);1348append(ct.target);1349append(p_arguments.size());1350append(p_function_name);1351ct.cleanup();1352}13531354void GDScriptByteCodeGenerator::write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) {1355append_opcode_and_argcount(GDScriptFunction::OPCODE_CALL_ASYNC, 2 + p_arguments.size());1356for (int i = 0; i < p_arguments.size(); i++) {1357append(p_arguments[i]);1358}1359append(GDScriptFunction::ADDR_SELF);1360CallTarget ct = get_call_target(p_target);1361append(ct.target);1362append(p_arguments.size());1363append(p_function_name);1364ct.cleanup();1365}13661367void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) {1368append_opcode_and_argcount(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL : GDScriptFunction::OPCODE_CALL_RETURN, 2 + p_arguments.size());1369for (int i = 0; i < p_arguments.size(); i++) {1370append(p_arguments[i]);1371}1372append(p_base);1373CallTarget ct = get_call_target(p_target);1374append(ct.target);1375append(p_arguments.size());1376append(p_function_name);1377ct.cleanup();1378}13791380void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) {1381append_opcode_and_argcount(p_use_self ? GDScriptFunction::OPCODE_CREATE_SELF_LAMBDA : GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());1382for (int i = 0; i < p_captures.size(); i++) {1383append(p_captures[i]);1384}13851386CallTarget ct = get_call_target(p_target);1387append(ct.target);1388append(p_captures.size());1389append(p_function);1390ct.cleanup();1391}13921393void GDScriptByteCodeGenerator::write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) {1394// Try to find an appropriate constructor.1395bool all_have_type = true;1396Vector<Variant::Type> arg_types;1397for (int i = 0; i < p_arguments.size(); i++) {1398if (!HAS_BUILTIN_TYPE(p_arguments[i])) {1399all_have_type = false;1400break;1401}1402arg_types.push_back(p_arguments[i].type.builtin_type);1403}1404if (all_have_type) {1405int valid_constructor = -1;1406for (int i = 0; i < Variant::get_constructor_count(p_type); i++) {1407if (Variant::get_constructor_argument_count(p_type, i) != p_arguments.size()) {1408continue;1409}1410int types_correct = true;1411for (int j = 0; j < arg_types.size(); j++) {1412if (arg_types[j] != Variant::get_constructor_argument_type(p_type, i, j)) {1413types_correct = false;1414break;1415}1416}1417if (types_correct) {1418valid_constructor = i;1419break;1420}1421}1422if (valid_constructor >= 0) {1423append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_VALIDATED, 1 + p_arguments.size());1424for (int i = 0; i < p_arguments.size(); i++) {1425append(p_arguments[i]);1426}1427CallTarget ct = get_call_target(p_target);1428append(ct.target);1429append(p_arguments.size());1430append(Variant::get_validated_constructor(p_type, valid_constructor));1431ct.cleanup();1432#ifdef DEBUG_ENABLED1433add_debug_name(constructors_names, get_constructor_pos(Variant::get_validated_constructor(p_type, valid_constructor)), Variant::get_type_name(p_type));1434#endif1435return;1436}1437}14381439append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT, 1 + p_arguments.size());1440for (int i = 0; i < p_arguments.size(); i++) {1441append(p_arguments[i]);1442}1443CallTarget ct = get_call_target(p_target);1444append(ct.target);1445append(p_arguments.size());1446append(p_type);1447ct.cleanup();1448}14491450void GDScriptByteCodeGenerator::write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) {1451append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_ARRAY, 1 + p_arguments.size());1452for (int i = 0; i < p_arguments.size(); i++) {1453append(p_arguments[i]);1454}1455CallTarget ct = get_call_target(p_target);1456append(ct.target);1457append(p_arguments.size());1458ct.cleanup();1459}14601461void GDScriptByteCodeGenerator::write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) {1462append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_ARRAY, 2 + p_arguments.size());1463for (int i = 0; i < p_arguments.size(); i++) {1464append(p_arguments[i]);1465}1466CallTarget ct = get_call_target(p_target);1467append(ct.target);1468append(get_constant_pos(p_element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1469append(p_arguments.size());1470append(p_element_type.builtin_type);1471append(p_element_type.native_type);1472ct.cleanup();1473}14741475void GDScriptByteCodeGenerator::write_construct_dictionary(const Address &p_target, const Vector<Address> &p_arguments) {1476append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_DICTIONARY, 1 + p_arguments.size());1477for (int i = 0; i < p_arguments.size(); i++) {1478append(p_arguments[i]);1479}1480CallTarget ct = get_call_target(p_target);1481append(ct.target);1482append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.1483ct.cleanup();1484}14851486void GDScriptByteCodeGenerator::write_construct_typed_dictionary(const Address &p_target, const GDScriptDataType &p_key_type, const GDScriptDataType &p_value_type, const Vector<Address> &p_arguments) {1487append_opcode_and_argcount(GDScriptFunction::OPCODE_CONSTRUCT_TYPED_DICTIONARY, 3 + p_arguments.size());1488for (int i = 0; i < p_arguments.size(); i++) {1489append(p_arguments[i]);1490}1491CallTarget ct = get_call_target(p_target);1492append(ct.target);1493append(get_constant_pos(p_key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1494append(get_constant_pos(p_value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1495append(p_arguments.size() / 2); // This is number of key-value pairs, so only half of actual arguments.1496append(p_key_type.builtin_type);1497append(p_key_type.native_type);1498append(p_value_type.builtin_type);1499append(p_value_type.native_type);1500ct.cleanup();1501}15021503void GDScriptByteCodeGenerator::write_await(const Address &p_target, const Address &p_operand) {1504append_opcode(GDScriptFunction::OPCODE_AWAIT);1505append(p_operand);1506append_opcode(GDScriptFunction::OPCODE_AWAIT_RESUME);1507append(p_target);1508}15091510void GDScriptByteCodeGenerator::write_if(const Address &p_condition) {1511append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);1512append(p_condition);1513if_jmp_addrs.push_back(opcodes.size());1514append(0); // Jump destination, will be patched.1515}15161517void GDScriptByteCodeGenerator::write_else() {1518append_opcode(GDScriptFunction::OPCODE_JUMP); // Jump from true if block;1519int else_jmp_addr = opcodes.size();1520append(0); // Jump destination, will be patched.15211522patch_jump(if_jmp_addrs.back()->get());1523if_jmp_addrs.pop_back();1524if_jmp_addrs.push_back(else_jmp_addr);1525}15261527void GDScriptByteCodeGenerator::write_endif() {1528patch_jump(if_jmp_addrs.back()->get());1529if_jmp_addrs.pop_back();1530}15311532void GDScriptByteCodeGenerator::write_jump_if_shared(const Address &p_value) {1533append_opcode(GDScriptFunction::OPCODE_JUMP_IF_SHARED);1534append(p_value);1535if_jmp_addrs.push_back(opcodes.size());1536append(0); // Jump destination, will be patched.1537}15381539void GDScriptByteCodeGenerator::write_end_jump_if_shared() {1540patch_jump(if_jmp_addrs.back()->get());1541if_jmp_addrs.pop_back();1542}15431544void GDScriptByteCodeGenerator::start_for(const GDScriptDataType &p_iterator_type, const GDScriptDataType &p_list_type, bool p_is_range) {1545Address counter(Address::LOCAL_VARIABLE, add_local("@counter_pos", p_iterator_type), p_iterator_type);15461547// Store state.1548for_counter_variables.push_back(counter);15491550if (p_is_range) {1551GDScriptDataType int_type;1552int_type.kind = GDScriptDataType::BUILTIN;1553int_type.builtin_type = Variant::INT;15541555Address range_from(Address::LOCAL_VARIABLE, add_local("@range_from", int_type), int_type);1556Address range_to(Address::LOCAL_VARIABLE, add_local("@range_to", int_type), int_type);1557Address range_step(Address::LOCAL_VARIABLE, add_local("@range_step", int_type), int_type);15581559// Store state.1560for_range_from_variables.push_back(range_from);1561for_range_to_variables.push_back(range_to);1562for_range_step_variables.push_back(range_step);1563} else {1564Address container(Address::LOCAL_VARIABLE, add_local("@container_pos", p_list_type), p_list_type);15651566// Store state.1567for_container_variables.push_back(container);1568}1569}15701571void GDScriptByteCodeGenerator::write_for_list_assignment(const Address &p_list) {1572const Address &container = for_container_variables.back()->get();15731574// Assign container.1575append_opcode(GDScriptFunction::OPCODE_ASSIGN);1576append(container);1577append(p_list);1578}15791580void GDScriptByteCodeGenerator::write_for_range_assignment(const Address &p_from, const Address &p_to, const Address &p_step) {1581const Address &range_from = for_range_from_variables.back()->get();1582const Address &range_to = for_range_to_variables.back()->get();1583const Address &range_step = for_range_step_variables.back()->get();15841585// Assign range args.1586if (range_from.type == p_from.type) {1587write_assign(range_from, p_from);1588} else {1589write_assign_with_conversion(range_from, p_from);1590}1591if (range_to.type == p_to.type) {1592write_assign(range_to, p_to);1593} else {1594write_assign_with_conversion(range_to, p_to);1595}1596if (range_step.type == p_step.type) {1597write_assign(range_step, p_step);1598} else {1599write_assign_with_conversion(range_step, p_step);1600}1601}16021603void GDScriptByteCodeGenerator::write_for(const Address &p_variable, bool p_use_conversion, bool p_is_range) {1604const Address &counter = for_counter_variables.back()->get();1605const Address &container = p_is_range ? Address() : for_container_variables.back()->get();1606const Address &range_from = p_is_range ? for_range_from_variables.back()->get() : Address();1607const Address &range_to = p_is_range ? for_range_to_variables.back()->get() : Address();1608const Address &range_step = p_is_range ? for_range_step_variables.back()->get() : Address();16091610current_breaks_to_patch.push_back(List<int>());16111612GDScriptFunction::Opcode begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN;1613GDScriptFunction::Opcode iterate_opcode = GDScriptFunction::OPCODE_ITERATE;16141615if (p_is_range) {1616begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_RANGE;1617iterate_opcode = GDScriptFunction::OPCODE_ITERATE_RANGE;1618} else if (container.type.has_type()) {1619if (container.type.kind == GDScriptDataType::BUILTIN) {1620switch (container.type.builtin_type) {1621case Variant::INT:1622begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_INT;1623iterate_opcode = GDScriptFunction::OPCODE_ITERATE_INT;1624break;1625case Variant::FLOAT:1626begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_FLOAT;1627iterate_opcode = GDScriptFunction::OPCODE_ITERATE_FLOAT;1628break;1629case Variant::VECTOR2:1630begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2;1631iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2;1632break;1633case Variant::VECTOR2I:1634begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR2I;1635iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR2I;1636break;1637case Variant::VECTOR3:1638begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3;1639iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3;1640break;1641case Variant::VECTOR3I:1642begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_VECTOR3I;1643iterate_opcode = GDScriptFunction::OPCODE_ITERATE_VECTOR3I;1644break;1645case Variant::STRING:1646begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_STRING;1647iterate_opcode = GDScriptFunction::OPCODE_ITERATE_STRING;1648break;1649case Variant::DICTIONARY:1650begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_DICTIONARY;1651iterate_opcode = GDScriptFunction::OPCODE_ITERATE_DICTIONARY;1652break;1653case Variant::ARRAY:1654begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_ARRAY;1655iterate_opcode = GDScriptFunction::OPCODE_ITERATE_ARRAY;1656break;1657case Variant::PACKED_BYTE_ARRAY:1658begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY;1659iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_BYTE_ARRAY;1660break;1661case Variant::PACKED_INT32_ARRAY:1662begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY;1663iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT32_ARRAY;1664break;1665case Variant::PACKED_INT64_ARRAY:1666begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY;1667iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_INT64_ARRAY;1668break;1669case Variant::PACKED_FLOAT32_ARRAY:1670begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY;1671iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT32_ARRAY;1672break;1673case Variant::PACKED_FLOAT64_ARRAY:1674begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY;1675iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_FLOAT64_ARRAY;1676break;1677case Variant::PACKED_STRING_ARRAY:1678begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY;1679iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_STRING_ARRAY;1680break;1681case Variant::PACKED_VECTOR2_ARRAY:1682begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY;1683iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR2_ARRAY;1684break;1685case Variant::PACKED_VECTOR3_ARRAY:1686begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY;1687iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR3_ARRAY;1688break;1689case Variant::PACKED_COLOR_ARRAY:1690begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY;1691iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_COLOR_ARRAY;1692break;1693case Variant::PACKED_VECTOR4_ARRAY:1694begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY;1695iterate_opcode = GDScriptFunction::OPCODE_ITERATE_PACKED_VECTOR4_ARRAY;1696break;1697default:1698break;1699}1700} else {1701begin_opcode = GDScriptFunction::OPCODE_ITERATE_BEGIN_OBJECT;1702iterate_opcode = GDScriptFunction::OPCODE_ITERATE_OBJECT;1703}1704}17051706Address temp;1707if (p_use_conversion) {1708temp = Address(Address::LOCAL_VARIABLE, add_local("@iterator_temp", GDScriptDataType()));1709}17101711// Begin loop.1712append_opcode(begin_opcode);1713append(counter);1714if (p_is_range) {1715append(range_from);1716append(range_to);1717append(range_step);1718} else {1719append(container);1720}1721append(p_use_conversion ? temp : p_variable);1722for_jmp_addrs.push_back(opcodes.size());1723append(0); // End of loop address, will be patched.1724append_opcode(GDScriptFunction::OPCODE_JUMP);1725append(opcodes.size() + (p_is_range ? 7 : 6)); // Skip over 'continue' code.17261727// Next iteration.1728int continue_addr = opcodes.size();1729continue_addrs.push_back(continue_addr);1730append_opcode(iterate_opcode);1731append(counter);1732if (p_is_range) {1733append(range_to);1734append(range_step);1735} else {1736append(container);1737}1738append(p_use_conversion ? temp : p_variable);1739for_jmp_addrs.push_back(opcodes.size());1740append(0); // Jump destination, will be patched.17411742if (p_use_conversion) {1743write_assign_with_conversion(p_variable, temp);1744if (p_variable.type.can_contain_object()) {1745clear_address(temp); // Can contain `RefCounted`, so clear it.1746}1747}1748}17491750void GDScriptByteCodeGenerator::write_endfor(bool p_is_range) {1751// Jump back to loop check.1752append_opcode(GDScriptFunction::OPCODE_JUMP);1753append(continue_addrs.back()->get());1754continue_addrs.pop_back();17551756// Patch end jumps (two of them).1757for (int i = 0; i < 2; i++) {1758patch_jump(for_jmp_addrs.back()->get());1759for_jmp_addrs.pop_back();1760}17611762// Patch break statements.1763for (const int &E : current_breaks_to_patch.back()->get()) {1764patch_jump(E);1765}1766current_breaks_to_patch.pop_back();17671768// Pop state.1769for_counter_variables.pop_back();1770if (p_is_range) {1771for_range_from_variables.pop_back();1772for_range_to_variables.pop_back();1773for_range_step_variables.pop_back();1774} else {1775for_container_variables.pop_back();1776}1777}17781779void GDScriptByteCodeGenerator::start_while_condition() {1780current_breaks_to_patch.push_back(List<int>());1781continue_addrs.push_back(opcodes.size());1782}17831784void GDScriptByteCodeGenerator::write_while(const Address &p_condition) {1785// Condition check.1786append_opcode(GDScriptFunction::OPCODE_JUMP_IF_NOT);1787append(p_condition);1788while_jmp_addrs.push_back(opcodes.size());1789append(0); // End of loop address, will be patched.1790}17911792void GDScriptByteCodeGenerator::write_endwhile() {1793// Jump back to loop check.1794append_opcode(GDScriptFunction::OPCODE_JUMP);1795append(continue_addrs.back()->get());1796continue_addrs.pop_back();17971798// Patch end jump.1799patch_jump(while_jmp_addrs.back()->get());1800while_jmp_addrs.pop_back();18011802// Patch break statements.1803for (const int &E : current_breaks_to_patch.back()->get()) {1804patch_jump(E);1805}1806current_breaks_to_patch.pop_back();1807}18081809void GDScriptByteCodeGenerator::write_break() {1810append_opcode(GDScriptFunction::OPCODE_JUMP);1811current_breaks_to_patch.back()->get().push_back(opcodes.size());1812append(0);1813}18141815void GDScriptByteCodeGenerator::write_continue() {1816append_opcode(GDScriptFunction::OPCODE_JUMP);1817append(continue_addrs.back()->get());1818}18191820void GDScriptByteCodeGenerator::write_breakpoint() {1821append_opcode(GDScriptFunction::OPCODE_BREAKPOINT);1822}18231824void GDScriptByteCodeGenerator::write_newline(int p_line) {1825if (GDScriptLanguage::get_singleton()->should_track_call_stack()) {1826// Add newline for debugger and stack tracking if enabled in the project settings.1827append_opcode(GDScriptFunction::OPCODE_LINE);1828append(p_line);1829current_line = p_line;1830}1831}18321833void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {1834if (!function->return_type.has_type() || p_return_value.type.has_type()) {1835// Either the function is untyped or the return value is also typed.18361837// If this is a typed function, then we need to check for potential conversions.1838if (function->return_type.has_type()) {1839if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {1840// Typed array.1841const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);1842append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);1843append(p_return_value);1844append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1845append(element_type.builtin_type);1846append(element_type.native_type);1847} else if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::DICTIONARY &&1848function->return_type.has_container_element_types()) {1849// Typed dictionary.1850const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);1851const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);1852append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);1853append(p_return_value);1854append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1855append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1856append(key_type.builtin_type);1857append(key_type.native_type);1858append(value_type.builtin_type);1859append(value_type.native_type);1860} 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) {1861// Add conversion.1862append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);1863append(p_return_value);1864append(function->return_type.builtin_type);1865} else {1866// Just assign.1867append_opcode(GDScriptFunction::OPCODE_RETURN);1868append(p_return_value);1869}1870} else {1871append_opcode(GDScriptFunction::OPCODE_RETURN);1872append(p_return_value);1873}1874} else {1875switch (function->return_type.kind) {1876case GDScriptDataType::BUILTIN: {1877if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type(0)) {1878const GDScriptDataType &element_type = function->return_type.get_container_element_type(0);1879append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY);1880append(p_return_value);1881append(get_constant_pos(element_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1882append(element_type.builtin_type);1883append(element_type.native_type);1884} else if (function->return_type.builtin_type == Variant::DICTIONARY && function->return_type.has_container_element_types()) {1885const GDScriptDataType &key_type = function->return_type.get_container_element_type_or_variant(0);1886const GDScriptDataType &value_type = function->return_type.get_container_element_type_or_variant(1);1887append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_DICTIONARY);1888append(p_return_value);1889append(get_constant_pos(key_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1890append(get_constant_pos(value_type.script_type) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS));1891append(key_type.builtin_type);1892append(key_type.native_type);1893append(value_type.builtin_type);1894append(value_type.native_type);1895} else {1896append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN);1897append(p_return_value);1898append(function->return_type.builtin_type);1899}1900} break;1901case GDScriptDataType::NATIVE: {1902append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE);1903append(p_return_value);1904int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];1905Variant nc = GDScriptLanguage::get_singleton()->get_global_array()[class_idx];1906class_idx = get_constant_pos(nc) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);1907append(class_idx);1908} break;1909case GDScriptDataType::GDSCRIPT:1910case GDScriptDataType::SCRIPT: {1911Variant script = function->return_type.script_type;1912int script_idx = get_constant_pos(script) | (GDScriptFunction::ADDR_TYPE_CONSTANT << GDScriptFunction::ADDR_BITS);19131914append_opcode(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT);1915append(p_return_value);1916append(script_idx);1917} break;1918default: {1919ERR_PRINT("Compiler bug: unresolved return.");19201921// Shouldn't get here, but fail-safe to a regular return;1922append_opcode(GDScriptFunction::OPCODE_RETURN);1923append(p_return_value);1924} break;1925}1926}1927}19281929void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {1930append_opcode(GDScriptFunction::OPCODE_ASSERT);1931append(p_test);1932append(p_message);1933}19341935void GDScriptByteCodeGenerator::start_block() {1936push_stack_identifiers();1937}19381939void GDScriptByteCodeGenerator::end_block() {1940pop_stack_identifiers();1941}19421943void GDScriptByteCodeGenerator::clear_temporaries() {1944for (int slot_idx : temporaries_pending_clear) {1945// The temporary may have been reused as something else since it was added to the list.1946// In that case, there's **no** need to clear it.1947if (temporaries[slot_idx].can_contain_object) {1948clear_address(Address(Address::TEMPORARY, slot_idx)); // Can contain `RefCounted`, so clear it.1949}1950}1951temporaries_pending_clear.clear();1952}19531954void GDScriptByteCodeGenerator::clear_address(const Address &p_address) {1955// Do not check `is_local_dirty()` here! Always clear the address since the codegen doesn't track the compiler.1956// Also, this method is used to initialize local variables of built-in types, since they cannot be `null`.19571958if (p_address.type.kind == GDScriptDataType::BUILTIN) {1959switch (p_address.type.builtin_type) {1960case Variant::BOOL:1961write_assign_false(p_address);1962break;1963case Variant::DICTIONARY:1964if (p_address.type.has_container_element_types()) {1965write_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>());1966} else {1967write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1968}1969break;1970case Variant::ARRAY:1971if (p_address.type.has_container_element_type(0)) {1972write_construct_typed_array(p_address, p_address.type.get_container_element_type(0), Vector<GDScriptCodeGenerator::Address>());1973} else {1974write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1975}1976break;1977case Variant::NIL:1978case Variant::OBJECT:1979write_assign_null(p_address);1980break;1981default:1982write_construct(p_address, p_address.type.builtin_type, Vector<GDScriptCodeGenerator::Address>());1983break;1984}1985} else {1986write_assign_null(p_address);1987}19881989if (p_address.mode == Address::LOCAL_VARIABLE) {1990dirty_locals.erase(p_address.address);1991}1992}19931994// Returns `true` if the local has been reused and not cleaned up with `clear_address()`.1995bool GDScriptByteCodeGenerator::is_local_dirty(const Address &p_address) const {1996ERR_FAIL_COND_V(p_address.mode != Address::LOCAL_VARIABLE, false);1997return dirty_locals.has(p_address.address);1998}19992000GDScriptByteCodeGenerator::~GDScriptByteCodeGenerator() {2001if (!ended && function != nullptr) {2002memdelete(function);2003}2004}200520062007