diff options
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 136 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.h | 78 | ||||
-rw-r--r-- | modules/gdscript/gdscript_disassembler.cpp | 71 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.h | 28 | ||||
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 176 |
5 files changed, 476 insertions, 13 deletions
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index cc8790c004..f0fa57ac57 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -170,6 +170,78 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() { function->_operator_funcs_ptr = nullptr; } + if (setters_map.size()) { + function->setters.resize(setters_map.size()); + function->_setters_count = function->setters.size(); + function->_setters_ptr = function->setters.ptr(); + for (const Map<Variant::ValidatedSetter, int>::Element *E = setters_map.front(); E; E = E->next()) { + function->setters.write[E->get()] = E->key(); + } + } else { + function->_setters_count = 0; + function->_setters_ptr = nullptr; + } + + if (getters_map.size()) { + function->getters.resize(getters_map.size()); + function->_getters_count = function->getters.size(); + function->_getters_ptr = function->getters.ptr(); + for (const Map<Variant::ValidatedGetter, int>::Element *E = getters_map.front(); E; E = E->next()) { + function->getters.write[E->get()] = E->key(); + } + } else { + function->_getters_count = 0; + function->_getters_ptr = nullptr; + } + + if (keyed_setters_map.size()) { + function->keyed_setters.resize(keyed_setters_map.size()); + function->_keyed_setters_count = function->keyed_setters.size(); + function->_keyed_setters_ptr = function->keyed_setters.ptr(); + for (const Map<Variant::ValidatedKeyedSetter, int>::Element *E = keyed_setters_map.front(); E; E = E->next()) { + function->keyed_setters.write[E->get()] = E->key(); + } + } else { + function->_keyed_setters_count = 0; + function->_keyed_setters_ptr = nullptr; + } + + if (keyed_getters_map.size()) { + function->keyed_getters.resize(keyed_getters_map.size()); + function->_keyed_getters_count = function->keyed_getters.size(); + function->_keyed_getters_ptr = function->keyed_getters.ptr(); + for (const Map<Variant::ValidatedKeyedGetter, int>::Element *E = keyed_getters_map.front(); E; E = E->next()) { + function->keyed_getters.write[E->get()] = E->key(); + } + } else { + function->_keyed_getters_count = 0; + function->_keyed_getters_ptr = nullptr; + } + + if (indexed_setters_map.size()) { + function->indexed_setters.resize(indexed_setters_map.size()); + function->_indexed_setters_count = function->indexed_setters.size(); + function->_indexed_setters_ptr = function->indexed_setters.ptr(); + for (const Map<Variant::ValidatedIndexedSetter, int>::Element *E = indexed_setters_map.front(); E; E = E->next()) { + function->indexed_setters.write[E->get()] = E->key(); + } + } else { + function->_indexed_setters_count = 0; + function->_indexed_setters_ptr = nullptr; + } + + if (indexed_getters_map.size()) { + function->indexed_getters.resize(indexed_getters_map.size()); + function->_indexed_getters_count = function->indexed_getters.size(); + function->_indexed_getters_ptr = function->indexed_getters.ptr(); + for (const Map<Variant::ValidatedIndexedGetter, int>::Element *E = indexed_getters_map.front(); E; E = E->next()) { + function->indexed_getters.write[E->get()] = E->key(); + } + } else { + function->_indexed_getters_count = 0; + function->_indexed_getters_ptr = nullptr; + } + if (debug_stack) { function->stack_debug = stack_debug; } @@ -193,6 +265,9 @@ void GDScriptByteCodeGenerator::set_initial_line(int p_line) { #define HAS_BUILTIN_TYPE(m_var) \ (m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN) +#define IS_BUILTIN_TYPE(m_var, m_type) \ + (m_var.type.has_type && m_var.type.kind == GDScriptDataType::BUILTIN && m_var.type.builtin_type == m_type) + void GDScriptByteCodeGenerator::write_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) { if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) { // Gather specific operator. @@ -324,20 +399,69 @@ void GDScriptByteCodeGenerator::write_end_ternary() { } void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) { - append(GDScriptFunction::OPCODE_SET, 3); + if (HAS_BUILTIN_TYPE(p_target)) { + if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type)) { + // Use indexed setter instead. + Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(p_target.type.builtin_type); + append(GDScriptFunction::OPCODE_SET_INDEXED_VALIDATED, 3); + append(p_target); + append(p_index); + append(p_source); + append(setter); + return; + } else if (Variant::get_member_validated_keyed_setter(p_target.type.builtin_type)) { + Variant::ValidatedKeyedSetter setter = Variant::get_member_validated_keyed_setter(p_target.type.builtin_type); + append(GDScriptFunction::OPCODE_SET_KEYED_VALIDATED, 3); + append(p_target); + append(p_index); + append(p_source); + append(setter); + return; + } + } + + append(GDScriptFunction::OPCODE_SET_KEYED, 3); append(p_target); append(p_index); append(p_source); } void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address &p_index, const Address &p_source) { - append(GDScriptFunction::OPCODE_GET, 3); + if (HAS_BUILTIN_TYPE(p_source)) { + if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_getter(p_source.type.builtin_type)) { + // Use indexed getter instead. + Variant::ValidatedIndexedGetter getter = Variant::get_member_validated_indexed_getter(p_source.type.builtin_type); + append(GDScriptFunction::OPCODE_GET_INDEXED_VALIDATED, 3); + append(p_source); + append(p_index); + append(p_target); + append(getter); + return; + } else if (Variant::get_member_validated_keyed_getter(p_source.type.builtin_type)) { + Variant::ValidatedKeyedGetter getter = Variant::get_member_validated_keyed_getter(p_source.type.builtin_type); + append(GDScriptFunction::OPCODE_GET_KEYED_VALIDATED, 3); + append(p_source); + append(p_index); + append(p_target); + append(getter); + return; + } + } + append(GDScriptFunction::OPCODE_GET_KEYED, 3); append(p_source); append(p_index); append(p_target); } void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) { + if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name)) { + Variant::ValidatedSetter setter = Variant::get_member_validated_setter(p_target.type.builtin_type, p_name); + append(GDScriptFunction::OPCODE_SET_NAMED_VALIDATED, 2); + append(p_target); + append(p_source); + append(setter); + return; + } append(GDScriptFunction::OPCODE_SET_NAMED, 2); append(p_target); append(p_source); @@ -345,6 +469,14 @@ void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const S } void GDScriptByteCodeGenerator::write_get_named(const Address &p_target, const StringName &p_name, const Address &p_source) { + if (HAS_BUILTIN_TYPE(p_source) && Variant::get_member_validated_getter(p_source.type.builtin_type, p_name)) { + Variant::ValidatedGetter getter = Variant::get_member_validated_getter(p_source.type.builtin_type, p_name); + append(GDScriptFunction::OPCODE_GET_NAMED_VALIDATED, 2); + append(p_source); + append(p_target); + append(getter); + return; + } append(GDScriptFunction::OPCODE_GET_NAMED, 2); append(p_source); append(p_target); diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h index cce17793f4..afb568fd6b 100644 --- a/modules/gdscript/gdscript_byte_codegen.h +++ b/modules/gdscript/gdscript_byte_codegen.h @@ -61,6 +61,12 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { Vector<StringName> named_globals; #endif Map<Variant::ValidatedOperatorEvaluator, int> operator_func_map; + Map<Variant::ValidatedSetter, int> setters_map; + Map<Variant::ValidatedGetter, int> getters_map; + Map<Variant::ValidatedKeyedSetter, int> keyed_setters_map; + Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map; + Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map; + Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map; List<int> if_jmp_addrs; // List since this can be nested. List<int> for_jmp_addrs; @@ -145,6 +151,54 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { return pos; } + int get_setter_pos(const Variant::ValidatedSetter p_setter) { + if (setters_map.has(p_setter)) + return setters_map[p_setter]; + int pos = setters_map.size(); + setters_map[p_setter] = pos; + return pos; + } + + int get_getter_pos(const Variant::ValidatedGetter p_getter) { + if (getters_map.has(p_getter)) + return getters_map[p_getter]; + int pos = getters_map.size(); + getters_map[p_getter] = pos; + return pos; + } + + int get_keyed_setter_pos(const Variant::ValidatedKeyedSetter p_keyed_setter) { + if (keyed_setters_map.has(p_keyed_setter)) + return keyed_setters_map[p_keyed_setter]; + int pos = keyed_setters_map.size(); + keyed_setters_map[p_keyed_setter] = pos; + return pos; + } + + int get_keyed_getter_pos(const Variant::ValidatedKeyedGetter p_keyed_getter) { + if (keyed_getters_map.has(p_keyed_getter)) + return keyed_getters_map[p_keyed_getter]; + int pos = keyed_getters_map.size(); + keyed_getters_map[p_keyed_getter] = pos; + return pos; + } + + int get_indexed_setter_pos(const Variant::ValidatedIndexedSetter p_indexed_setter) { + if (indexed_setters_map.has(p_indexed_setter)) + return indexed_setters_map[p_indexed_setter]; + int pos = indexed_setters_map.size(); + indexed_setters_map[p_indexed_setter] = pos; + return pos; + } + + int get_indexed_getter_pos(const Variant::ValidatedIndexedGetter p_indexed_getter) { + if (indexed_getters_map.has(p_indexed_getter)) + return indexed_getters_map[p_indexed_getter]; + int pos = indexed_getters_map.size(); + indexed_getters_map[p_indexed_getter] = pos; + return pos; + } + void alloc_stack(int p_level) { if (p_level >= stack_max) stack_max = p_level + 1; @@ -204,6 +258,30 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator { opcodes.push_back(get_operation_pos(p_operation)); } + void append(const Variant::ValidatedSetter p_setter) { + opcodes.push_back(get_setter_pos(p_setter)); + } + + void append(const Variant::ValidatedGetter p_getter) { + opcodes.push_back(get_getter_pos(p_getter)); + } + + void append(const Variant::ValidatedKeyedSetter p_keyed_setter) { + opcodes.push_back(get_keyed_setter_pos(p_keyed_setter)); + } + + void append(const Variant::ValidatedKeyedGetter p_keyed_getter) { + opcodes.push_back(get_keyed_getter_pos(p_keyed_getter)); + } + + void append(const Variant::ValidatedIndexedSetter p_indexed_setter) { + opcodes.push_back(get_indexed_setter_pos(p_indexed_setter)); + } + + void append(const Variant::ValidatedIndexedGetter p_indexed_getter) { + opcodes.push_back(get_indexed_getter_pos(p_indexed_getter)); + } + void patch_jump(int p_address) { opcodes.write[p_address] = opcodes.size(); } diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index 2540940332..ce0cc768a6 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -167,8 +167,8 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 4; } break; - case OPCODE_SET: { - text += "set "; + case OPCODE_SET_KEYED: { + text += "set keyed "; text += DADDR(1); text += "["; text += DADDR(2); @@ -177,8 +177,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 4; } break; - case OPCODE_GET: { - text += "get "; + case OPCODE_SET_KEYED_VALIDATED: { + text += "set keyed validated "; + text += DADDR(1); + text += "["; + text += DADDR(2); + text += "] = "; + text += DADDR(3); + + incr += 5; + } break; + case OPCODE_SET_INDEXED_VALIDATED: { + text += "set indexed validated "; + text += DADDR(1); + text += "["; + text += DADDR(2); + text += "] = "; + text += DADDR(3); + + incr += 5; + } break; + case OPCODE_GET_KEYED: { + text += "get keyed "; text += DADDR(3); text += " = "; text += DADDR(1); @@ -188,6 +208,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 4; } break; + case OPCODE_GET_KEYED_VALIDATED: { + text += "get keyed validated "; + text += DADDR(3); + text += " = "; + text += DADDR(1); + text += "["; + text += DADDR(2); + text += "]"; + + incr += 5; + } break; + case OPCODE_GET_INDEXED_VALIDATED: { + text += "get indexed validated "; + text += DADDR(3); + text += " = "; + text += DADDR(1); + text += "["; + text += DADDR(2); + text += "]"; + + incr += 5; + } break; case OPCODE_SET_NAMED: { text += "set_named "; text += DADDR(1); @@ -198,6 +240,16 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 4; } break; + case OPCODE_SET_NAMED_VALIDATED: { + text += "set_named validated "; + text += DADDR(1); + text += "[\""; + text += "<unknown name>"; + text += "\"] = "; + text += DADDR(2); + + incr += 4; + } break; case OPCODE_GET_NAMED: { text += "get_named "; text += DADDR(2); @@ -209,6 +261,17 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { incr += 4; } break; + case OPCODE_GET_NAMED_VALIDATED: { + text += "get_named validated "; + text += DADDR(2); + text += " = "; + text += DADDR(1); + text += "[\""; + text += "<unknown name>"; + text += "\"]"; + + incr += 4; + } break; case OPCODE_SET_MEMBER: { text += "set_member "; text += "[\""; diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 94cd30955c..061618a426 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -162,10 +162,16 @@ public: OPCODE_OPERATOR_VALIDATED, OPCODE_EXTENDS_TEST, OPCODE_IS_BUILTIN, - OPCODE_SET, - OPCODE_GET, + OPCODE_SET_KEYED, + OPCODE_SET_KEYED_VALIDATED, + OPCODE_SET_INDEXED_VALIDATED, + OPCODE_GET_KEYED, + OPCODE_GET_KEYED_VALIDATED, + OPCODE_GET_INDEXED_VALIDATED, OPCODE_SET_NAMED, + OPCODE_SET_NAMED_VALIDATED, OPCODE_GET_NAMED, + OPCODE_GET_NAMED_VALIDATED, OPCODE_SET_MEMBER, OPCODE_GET_MEMBER, OPCODE_ASSIGN, @@ -244,6 +250,18 @@ private: int _default_arg_count = 0; int _operator_funcs_count = 0; const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr; + int _setters_count = 0; + const Variant::ValidatedSetter *_setters_ptr = nullptr; + int _getters_count = 0; + const Variant::ValidatedGetter *_getters_ptr = nullptr; + int _keyed_setters_count = 0; + const Variant::ValidatedKeyedSetter *_keyed_setters_ptr = nullptr; + int _keyed_getters_count = 0; + const Variant::ValidatedKeyedGetter *_keyed_getters_ptr = nullptr; + int _indexed_setters_count = 0; + const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr; + int _indexed_getters_count = 0; + const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr; const int *_code_ptr = nullptr; int _code_size = 0; int _argument_count = 0; @@ -260,6 +278,12 @@ private: Vector<StringName> global_names; Vector<int> default_arguments; Vector<Variant::ValidatedOperatorEvaluator> operator_funcs; + Vector<Variant::ValidatedSetter> setters; + Vector<Variant::ValidatedGetter> getters; + Vector<Variant::ValidatedKeyedSetter> keyed_setters; + Vector<Variant::ValidatedKeyedGetter> keyed_getters; + Vector<Variant::ValidatedIndexedSetter> indexed_setters; + Vector<Variant::ValidatedIndexedGetter> indexed_getters; Vector<int> code; Vector<GDScriptDataType> argument_types; GDScriptDataType return_type; diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index ab923ec37c..69180edea4 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -191,10 +191,16 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_OPERATOR_VALIDATED, \ &&OPCODE_EXTENDS_TEST, \ &&OPCODE_IS_BUILTIN, \ - &&OPCODE_SET, \ - &&OPCODE_GET, \ + &&OPCODE_SET_KEYED, \ + &&OPCODE_SET_KEYED_VALIDATED, \ + &&OPCODE_SET_INDEXED_VALIDATED, \ + &&OPCODE_GET_KEYED, \ + &&OPCODE_GET_KEYED_VALIDATED, \ + &&OPCODE_GET_INDEXED_VALIDATED, \ &&OPCODE_SET_NAMED, \ + &&OPCODE_SET_NAMED_VALIDATED, \ &&OPCODE_GET_NAMED, \ + &&OPCODE_GET_NAMED_VALIDATED, \ &&OPCODE_SET_MEMBER, \ &&OPCODE_GET_MEMBER, \ &&OPCODE_ASSIGN, \ @@ -575,7 +581,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; - OPCODE(OPCODE_SET) { + OPCODE(OPCODE_SET_KEYED) { CHECK_SPACE(3); GET_INSTRUCTION_ARG(dst, 0); @@ -601,7 +607,69 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; - OPCODE(OPCODE_GET) { + OPCODE(OPCODE_SET_KEYED_VALIDATED) { + CHECK_SPACE(4); + + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(index, 1); + GET_INSTRUCTION_ARG(value, 2); + + int index_setter = _code_ptr[ip + 4]; + GD_ERR_BREAK(index_setter < 0 || index_setter >= _keyed_setters_count); + const Variant::ValidatedKeyedSetter setter = _keyed_setters_ptr[index_setter]; + + bool valid; + setter(dst, index, value, valid); + +#ifdef DEBUG_ENABLED + if (!valid) { + String v = index->operator String(); + if (v != "") { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(index) + "'"; + } + err_text = "Invalid set index " + v + " (on base: '" + _get_var_type(dst) + "') with value of type '" + _get_var_type(value) + "'"; + OPCODE_BREAK; + } +#endif + ip += 5; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_SET_INDEXED_VALIDATED) { + CHECK_SPACE(4); + + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(index, 1); + GET_INSTRUCTION_ARG(value, 2); + + int index_setter = _code_ptr[ip + 4]; + GD_ERR_BREAK(index_setter < 0 || index_setter >= _indexed_setters_count); + const Variant::ValidatedIndexedSetter setter = _indexed_setters_ptr[index_setter]; + + int64_t int_index = *VariantInternal::get_int(index); + + bool oob; + setter(dst, int_index, value, oob); + +#ifdef DEBUG_ENABLED + if (oob) { + String v = index->operator String(); + if (v != "") { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(index) + "'"; + } + err_text = "Out of bounds set index " + v + " (on base: '" + _get_var_type(dst) + "')"; + OPCODE_BREAK; + } +#endif + ip += 5; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_GET_KEYED) { CHECK_SPACE(3); GET_INSTRUCTION_ARG(src, 0); @@ -610,7 +678,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a bool valid; #ifdef DEBUG_ENABLED - //allow better error message in cases where src and dst are the same stack position + // Allow better error message in cases where src and dst are the same stack position. Variant ret = src->get(*index, &valid); #else *dst = src->get(*index, &valid); @@ -633,6 +701,74 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_GET_KEYED_VALIDATED) { + CHECK_SPACE(4); + + GET_INSTRUCTION_ARG(src, 0); + GET_INSTRUCTION_ARG(key, 1); + GET_INSTRUCTION_ARG(dst, 2); + + int index_getter = _code_ptr[ip + 4]; + GD_ERR_BREAK(index_getter < 0 || index_getter >= _keyed_getters_count); + const Variant::ValidatedKeyedGetter getter = _keyed_getters_ptr[index_getter]; + + bool valid; +#ifdef DEBUG_ENABLED + // Allow better error message in cases where src and dst are the same stack position. + Variant ret; + getter(src, key, &ret, valid); +#else + getter(src, key, dst, valid); +#endif +#ifdef DEBUG_ENABLED + if (!valid) { + String v = key->operator String(); + if (v != "") { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(key) + "'"; + } + err_text = "Invalid get index " + v + " (on base: '" + _get_var_type(src) + "')."; + OPCODE_BREAK; + } + *dst = ret; +#endif + ip += 5; + } + DISPATCH_OPCODE; + + OPCODE(OPCODE_GET_INDEXED_VALIDATED) { + CHECK_SPACE(4); + + GET_INSTRUCTION_ARG(src, 0); + GET_INSTRUCTION_ARG(index, 1); + GET_INSTRUCTION_ARG(dst, 2); + + int index_getter = _code_ptr[ip + 4]; + GD_ERR_BREAK(index_getter < 0 || index_getter >= _indexed_getters_count); + const Variant::ValidatedIndexedGetter getter = _indexed_getters_ptr[index_getter]; + + int64_t int_index = *VariantInternal::get_int(index); + + bool oob; + getter(src, int_index, dst, oob); + +#ifdef DEBUG_ENABLED + if (oob) { + String v = index->operator String(); + if (v != "") { + v = "'" + v + "'"; + } else { + v = "of type '" + _get_var_type(index) + "'"; + } + err_text = "Out of bounds get index " + v + " (on base: '" + _get_var_type(src) + "')"; + OPCODE_BREAK; + } +#endif + ip += 5; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_SET_NAMED) { CHECK_SPACE(3); @@ -658,6 +794,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_SET_NAMED_VALIDATED) { + CHECK_SPACE(3); + + GET_INSTRUCTION_ARG(dst, 0); + GET_INSTRUCTION_ARG(value, 1); + + int index_setter = _code_ptr[ip + 3]; + GD_ERR_BREAK(index_setter < 0 || index_setter >= _setters_count); + const Variant::ValidatedSetter setter = _setters_ptr[index_setter]; + + setter(dst, value); + ip += 4; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_GET_NAMED) { CHECK_SPACE(4); @@ -692,6 +843,21 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a } DISPATCH_OPCODE; + OPCODE(OPCODE_GET_NAMED_VALIDATED) { + CHECK_SPACE(3); + + GET_INSTRUCTION_ARG(src, 0); + GET_INSTRUCTION_ARG(dst, 1); + + int index_getter = _code_ptr[ip + 3]; + GD_ERR_BREAK(index_getter < 0 || index_getter >= _getters_count); + const Variant::ValidatedGetter getter = _getters_ptr[index_getter]; + + getter(src, dst); + ip += 4; + } + DISPATCH_OPCODE; + OPCODE(OPCODE_SET_MEMBER) { CHECK_SPACE(3); GET_INSTRUCTION_ARG(src, 0); |