diff options
Diffstat (limited to 'modules/gdscript/gdscript_vm.cpp')
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 192 |
1 files changed, 188 insertions, 4 deletions
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index ffc871bdcb..6b7da4a467 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -128,7 +128,10 @@ Variant *GDScriptFunction::_get_variant(int p_address, GDScriptInstance *p_insta #ifdef DEBUG_ENABLED static String _get_script_name(const Ref<Script> p_script) { - if (p_script->get_name().is_empty()) { + Ref<GDScript> gdscript = p_script; + if (gdscript.is_valid()) { + return gdscript->get_script_class_name(); + } else if (p_script->get_name().is_empty()) { return p_script->get_path().get_file(); } else { return p_script->get_name(); @@ -293,6 +296,10 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const &&OPCODE_JUMP_IF_NOT, \ &&OPCODE_JUMP_TO_DEF_ARGUMENT, \ &&OPCODE_RETURN, \ + &&OPCODE_RETURN_TYPED_BUILTIN, \ + &&OPCODE_RETURN_TYPED_ARRAY, \ + &&OPCODE_RETURN_TYPED_NATIVE, \ + &&OPCODE_RETURN_TYPED_SCRIPT, \ &&OPCODE_ITERATE_BEGIN, \ &&OPCODE_ITERATE_BEGIN_INT, \ &&OPCODE_ITERATE_BEGIN_FLOAT, \ @@ -569,7 +576,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED OPCODE_WHILE(ip < _code_size) { - int last_opcode = _code_ptr[ip]; + int last_opcode = _code_ptr[ip] & INSTR_MASK; #else OPCODE_WHILE(true) { #endif @@ -1113,14 +1120,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a #ifdef DEBUG_ENABLED err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) + "' to a variable of type '" + +"'."; - OPCODE_BREAK; #endif + OPCODE_BREAK; } if (!dst_arr->typed_assign(*src)) { #ifdef DEBUG_ENABLED err_text = "Trying to assign a typed array with an array of different type.'"; - OPCODE_BREAK; #endif + OPCODE_BREAK; } ip += 3; @@ -2143,6 +2150,183 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; } + OPCODE(OPCODE_RETURN_TYPED_BUILTIN) { + CHECK_SPACE(3); + GET_INSTRUCTION_ARG(r, 0); + + Variant::Type ret_type = (Variant::Type)_code_ptr[ip + 2]; + GD_ERR_BREAK(ret_type < 0 || ret_type >= Variant::VARIANT_MAX); + + if (r->get_type() != ret_type) { + if (Variant::can_convert_strict(r->get_type(), ret_type)) { + Callable::CallError ce; + Variant::construct(ret_type, retvalue, const_cast<const Variant **>(&r), 1, ce); + } else { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + Variant::get_type_name(r->get_type()), Variant::get_type_name(ret_type)); +#endif // DEBUG_ENABLED + + // Construct a base type anyway so type constraints are met. + Callable::CallError ce; + Variant::construct(ret_type, retvalue, nullptr, 0, ce); + OPCODE_BREAK; + } + } else { + retvalue = *r; + } +#ifdef DEBUG_ENABLED + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + OPCODE(OPCODE_RETURN_TYPED_ARRAY) { + CHECK_SPACE(5); + GET_INSTRUCTION_ARG(r, 0); + + GET_INSTRUCTION_ARG(script_type, 1); + Variant::Type builtin_type = (Variant::Type)_code_ptr[ip + 3]; + int native_type_idx = _code_ptr[ip + 4]; + GD_ERR_BREAK(native_type_idx < 0 || native_type_idx >= _global_names_count); + const StringName native_type = _global_names_ptr[native_type_idx]; + + if (r->get_type() != Variant::ARRAY) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "Array[%s]".)", + Variant::get_type_name(r->get_type()), Variant::get_type_name(builtin_type)); +#endif + OPCODE_BREAK; + } + + Array array; + array.set_typed(builtin_type, native_type, script_type); + +#ifdef DEBUG_ENABLED + bool valid = array.typed_assign(*VariantInternal::get_array(r)); +#else + array.typed_assign(*VariantInternal::get_array(r)); +#endif // DEBUG_ENABLED + + // Assign the return value anyway since we want it to be the valid type. + retvalue = array; + +#ifdef DEBUG_ENABLED + if (!valid) { + err_text = "Trying to return a typed array with an array of different type.'"; + OPCODE_BREAK; + } + + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + OPCODE(OPCODE_RETURN_TYPED_NATIVE) { + CHECK_SPACE(3); + GET_INSTRUCTION_ARG(r, 0); + + GET_INSTRUCTION_ARG(type, 1); + GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *()); + GD_ERR_BREAK(!nc); + + if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) { + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + Variant::get_type_name(r->get_type()), nc->get_name()); + OPCODE_BREAK; + } + +#ifdef DEBUG_ENABLED + bool freed = false; + Object *ret_obj = r->get_validated_object_with_check(freed); + + if (freed) { + err_text = "Trying to return a previously freed instance."; + OPCODE_BREAK; + } +#else + Object *ret_obj = r->operator Object *(); +#endif // DEBUG_ENABLED + if (ret_obj && !ClassDB::is_parent_class(ret_obj->get_class_name(), nc->get_name())) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + ret_obj->get_class_name(), nc->get_name()); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + retvalue = *r; + +#ifdef DEBUG_ENABLED + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + OPCODE(OPCODE_RETURN_TYPED_SCRIPT) { + CHECK_SPACE(3); + GET_INSTRUCTION_ARG(r, 0); + + GET_INSTRUCTION_ARG(type, 1); + Script *base_type = Object::cast_to<Script>(type->operator Object *()); + GD_ERR_BREAK(!base_type); + + if (r->get_type() != Variant::OBJECT && r->get_type() != Variant::NIL) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + Variant::get_type_name(r->get_type()), _get_script_name(Ref<Script>(base_type))); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + +#ifdef DEBUG_ENABLED + bool freed = false; + Object *ret_obj = r->get_validated_object_with_check(freed); + + if (freed) { + err_text = "Trying to return a previously freed instance."; + OPCODE_BREAK; + } +#else + Object *ret_obj = r->operator Object *(); +#endif // DEBUG_ENABLED + + if (ret_obj) { + ScriptInstance *ret_inst = ret_obj->get_script_instance(); + if (!ret_inst) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + ret_obj->get_class_name(), _get_script_name(Ref<GDScript>(base_type))); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + + Script *ret_type = ret_obj->get_script_instance()->get_script().ptr(); + bool valid = false; + + while (ret_type) { + if (ret_type == base_type) { + valid = true; + break; + } + ret_type = ret_type->get_base_script().ptr(); + } + + if (!valid) { +#ifdef DEBUG_ENABLED + err_text = vformat(R"(Trying to return value of type "%s" from a function which the return type is "%s".)", + _get_script_name(ret_obj->get_script_instance()->get_script()), _get_script_name(Ref<GDScript>(base_type))); +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + } + retvalue = *r; + +#ifdef DEBUG_ENABLED + exit_ok = true; +#endif // DEBUG_ENABLED + OPCODE_BREAK; + } + OPCODE(OPCODE_ITERATE_BEGIN) { CHECK_SPACE(8); // Space for this and a regular iterate. |