2020-11-12 10:14:48 -03:00
/**************************************************************************/
/* gdscript_vm.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2023-06-13 16:56:21 +02:00
# include "gdscript.h"
2020-11-12 10:14:48 -03:00
# include "gdscript_function.h"
2023-06-13 16:56:21 +02:00
# include "gdscript_lambda_callable.h"
2020-11-12 10:14:48 -03:00
# include "core/os/os.h"
# ifdef DEBUG_ENABLED
2023-03-05 14:37:11 +02:00
static bool _profile_count_as_native ( const Object * p_base_obj , const StringName & p_methodname ) {
if ( ! p_base_obj ) {
return false ;
}
StringName cname = p_base_obj - > get_class_name ( ) ;
if ( ( p_methodname = = " new " & & cname = = " GDScript " ) | | p_methodname = = " call " ) {
return false ;
}
return ClassDB : : class_exists ( cname ) & & ClassDB : : has_method ( cname , p_methodname , false ) ;
}
2022-11-27 09:56:53 +02:00
static String _get_element_type ( Variant : : Type builtin_type , const StringName & native_type , const Ref < Script > & script_type ) {
if ( script_type . is_valid ( ) & & script_type - > is_valid ( ) ) {
2023-06-20 12:03:54 +03:00
return GDScript : : debug_get_script_name ( script_type ) ;
2022-11-27 09:56:53 +02:00
} else if ( native_type ! = StringName ( ) ) {
return native_type . operator String ( ) ;
} else {
return Variant : : get_type_name ( builtin_type ) ;
}
}
2020-11-12 10:14:48 -03:00
static String _get_var_type ( const Variant * p_var ) {
String basestr ;
if ( p_var - > get_type ( ) = = Variant : : OBJECT ) {
bool was_freed ;
Object * bobj = p_var - > get_validated_object_with_check ( was_freed ) ;
if ( ! bobj ) {
if ( was_freed ) {
basestr = " previously freed " ;
2021-09-27 13:58:46 +02:00
} else {
basestr = " null instance " ;
2020-11-12 10:14:48 -03:00
}
} else {
2022-04-06 14:14:38 -03:00
if ( bobj - > is_class_ptr ( GDScriptNativeClass : : get_class_ptr_static ( ) ) ) {
basestr = Object : : cast_to < GDScriptNativeClass > ( bobj ) - > get_name ( ) ;
} else {
basestr = bobj - > get_class ( ) ;
if ( bobj - > get_script_instance ( ) ) {
2023-06-20 12:03:54 +03:00
basestr + = " ( " + GDScript : : debug_get_script_name ( bobj - > get_script_instance ( ) - > get_script ( ) ) + " ) " ;
2022-04-06 14:14:38 -03:00
}
2020-11-12 10:14:48 -03:00
}
}
} else {
2021-03-09 12:32:35 -03:00
if ( p_var - > get_type ( ) = = Variant : : ARRAY ) {
basestr = " Array " ;
const Array * p_array = VariantInternal : : get_array ( p_var ) ;
Variant : : Type builtin_type = ( Variant : : Type ) p_array - > get_typed_builtin ( ) ;
2022-11-27 09:56:53 +02:00
if ( builtin_type ! = Variant : : NIL ) {
basestr + = " [ " + _get_element_type ( builtin_type , p_array - > get_typed_class_name ( ) , p_array - > get_typed_script ( ) ) + " ] " ;
2021-03-09 12:32:35 -03:00
}
} else {
basestr = Variant : : get_type_name ( p_var - > get_type ( ) ) ;
}
2020-11-12 10:14:48 -03:00
}
return basestr ;
}
2023-03-05 14:37:11 +02:00
void GDScriptFunction : : _profile_native_call ( uint64_t p_t_taken , const String & p_func_name , const String & p_instance_class_name ) {
HashMap < String , Profile : : NativeProfile > : : Iterator inner_prof = profile . native_calls . find ( p_func_name ) ;
if ( inner_prof ) {
inner_prof - > value . call_count + = 1 ;
} else {
String sig = vformat ( " %s::0::%s%s%s " , get_script ( ) - > get_script_path ( ) , p_instance_class_name , p_instance_class_name . is_empty ( ) ? " " : " . " , p_func_name ) ;
inner_prof = profile . native_calls . insert ( p_func_name , Profile : : NativeProfile { 1 , 0 , sig } ) ;
}
inner_prof - > value . total_time + = p_t_taken ;
}
2020-11-12 10:14:48 -03:00
# endif // DEBUG_ENABLED
2022-02-17 15:18:43 +00:00
Variant GDScriptFunction : : _get_default_variant_for_data_type ( const GDScriptDataType & p_data_type ) {
if ( p_data_type . kind = = GDScriptDataType : : BUILTIN ) {
if ( p_data_type . builtin_type = = Variant : : ARRAY ) {
Array array ;
// Typed array.
2023-09-14 13:31:07 -05:00
if ( p_data_type . has_container_element_type ( 0 ) ) {
const GDScriptDataType & element_type = p_data_type . get_container_element_type ( 0 ) ;
2022-11-27 09:56:53 +02:00
array . set_typed ( element_type . builtin_type , element_type . native_type , element_type . script_type ) ;
2022-02-17 15:18:43 +00:00
}
return array ;
} else {
Callable : : CallError ce ;
Variant variant ;
Variant : : construct ( p_data_type . builtin_type , variant , nullptr , 0 , ce ) ;
ERR_FAIL_COND_V ( ce . error ! = Callable : : CallError : : CALL_OK , Variant ( ) ) ;
return variant ;
}
}
return Variant ( ) ;
}
2020-11-12 10:14:48 -03:00
String GDScriptFunction : : _get_call_error ( const Callable : : CallError & p_err , const String & p_where , const Variant * * argptrs ) const {
String err_text ;
if ( p_err . error = = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ) {
int errorarg = p_err . argument ;
2023-09-12 21:55:55 +03:00
ERR_FAIL_COND_V_MSG ( errorarg < 0 | | argptrs [ errorarg ] = = nullptr , " GDScript bug (please report): Invalid CallError argument index or null pointer. " , " Invalid CallError argument index or null pointer. " ) ;
2020-11-12 10:14:48 -03:00
// Handle the Object to Object case separately as we don't have further class details.
# ifdef DEBUG_ENABLED
if ( p_err . expected = = Variant : : OBJECT & & argptrs [ errorarg ] - > get_type ( ) = = p_err . expected ) {
err_text = " Invalid type in " + p_where + " . The Object-derived class of argument " + itos ( errorarg + 1 ) + " ( " + _get_var_type ( argptrs [ errorarg ] ) + " ) is not a subclass of the expected argument class. " ;
2022-11-27 09:56:53 +02:00
} else if ( p_err . expected = = Variant : : ARRAY & & argptrs [ errorarg ] - > get_type ( ) = = p_err . expected ) {
err_text = " Invalid type in " + p_where + " . The array of argument " + itos ( errorarg + 1 ) + " ( " + _get_var_type ( argptrs [ errorarg ] ) + " ) does not have the same element type as the expected typed array argument. " ;
2020-11-12 10:14:48 -03:00
} else
# endif // DEBUG_ENABLED
{
err_text = " Invalid type in " + p_where + " . Cannot convert argument " + itos ( errorarg + 1 ) + " from " + Variant : : get_type_name ( argptrs [ errorarg ] - > get_type ( ) ) + " to " + Variant : : get_type_name ( Variant : : Type ( p_err . expected ) ) + " . " ;
}
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ) {
2023-09-12 21:55:55 +03:00
err_text = " Invalid call to " + p_where + " . Expected " + itos ( p_err . expected ) + " arguments. " ;
2020-11-12 10:14:48 -03:00
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ) {
2023-09-12 21:55:55 +03:00
err_text = " Invalid call to " + p_where + " . Expected " + itos ( p_err . expected ) + " arguments. " ;
2020-11-12 10:14:48 -03:00
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) {
err_text = " Invalid call. Nonexistent " + p_where + " . " ;
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_INSTANCE_IS_NULL ) {
err_text = " Attempt to call " + p_where + " on a null instance. " ;
2022-06-27 13:10:04 -07:00
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_METHOD_NOT_CONST ) {
err_text = " Attempt to call " + p_where + " on a const instance. " ;
2020-11-12 10:14:48 -03:00
} else {
err_text = " Bug, call error: # " + itos ( p_err . error ) ;
}
return err_text ;
}
2021-05-17 10:59:43 -03:00
void ( * type_init_function_table [ ] ) ( Variant * ) = {
nullptr , // NIL (shouldn't be called).
& VariantInitializer < bool > : : init , // BOOL.
& VariantInitializer < int64_t > : : init , // INT.
& VariantInitializer < double > : : init , // FLOAT.
& VariantInitializer < String > : : init , // STRING.
& VariantInitializer < Vector2 > : : init , // VECTOR2.
& VariantInitializer < Vector2i > : : init , // VECTOR2I.
& VariantInitializer < Rect2 > : : init , // RECT2.
& VariantInitializer < Rect2i > : : init , // RECT2I.
& VariantInitializer < Vector3 > : : init , // VECTOR3.
& VariantInitializer < Vector3i > : : init , // VECTOR3I.
& VariantInitializer < Transform2D > : : init , // TRANSFORM2D.
2022-07-20 01:11:13 +02:00
& VariantInitializer < Vector4 > : : init , // VECTOR4.
& VariantInitializer < Vector4i > : : init , // VECTOR4I.
2021-05-17 10:59:43 -03:00
& VariantInitializer < Plane > : : init , // PLANE.
2021-01-20 07:02:02 +00:00
& VariantInitializer < Quaternion > : : init , // QUATERNION.
2021-05-17 10:59:43 -03:00
& VariantInitializer < AABB > : : init , // AABB.
& VariantInitializer < Basis > : : init , // BASIS.
2020-10-17 01:08:21 -04:00
& VariantInitializer < Transform3D > : : init , // TRANSFORM3D.
2022-07-20 01:11:13 +02:00
& VariantInitializer < Projection > : : init , // PROJECTION.
2021-05-17 10:59:43 -03:00
& VariantInitializer < Color > : : init , // COLOR.
& VariantInitializer < StringName > : : init , // STRING_NAME.
& VariantInitializer < NodePath > : : init , // NODE_PATH.
& VariantInitializer < RID > : : init , // RID.
2021-08-19 20:19:47 -03:00
& VariantInitializer < Object * > : : init , // OBJECT.
2021-05-17 10:59:43 -03:00
& VariantInitializer < Callable > : : init , // CALLABLE.
& VariantInitializer < Signal > : : init , // SIGNAL.
& VariantInitializer < Dictionary > : : init , // DICTIONARY.
& VariantInitializer < Array > : : init , // ARRAY.
& VariantInitializer < PackedByteArray > : : init , // PACKED_BYTE_ARRAY.
& VariantInitializer < PackedInt32Array > : : init , // PACKED_INT32_ARRAY.
& VariantInitializer < PackedInt64Array > : : init , // PACKED_INT64_ARRAY.
& VariantInitializer < PackedFloat32Array > : : init , // PACKED_FLOAT32_ARRAY.
& VariantInitializer < PackedFloat64Array > : : init , // PACKED_FLOAT64_ARRAY.
& VariantInitializer < PackedStringArray > : : init , // PACKED_STRING_ARRAY.
& VariantInitializer < PackedVector2Array > : : init , // PACKED_VECTOR2_ARRAY.
& VariantInitializer < PackedVector3Array > : : init , // PACKED_VECTOR3_ARRAY.
& VariantInitializer < PackedColorArray > : : init , // PACKED_COLOR_ARRAY.
2024-04-08 07:51:34 -07:00
& VariantInitializer < PackedVector4Array > : : init , // PACKED_VECTOR4_ARRAY.
2021-05-17 10:59:43 -03:00
} ;
2020-11-12 10:14:48 -03:00
# if defined(__GNUC__)
2024-04-25 21:05:53 -03:00
# define OPCODES_TABLE \
static const void *switch_table_ops[] = { \
&&OPCODE_OPERATOR, \
&&OPCODE_OPERATOR_VALIDATED, \
&&OPCODE_TYPE_TEST_BUILTIN, \
&&OPCODE_TYPE_TEST_ARRAY, \
&&OPCODE_TYPE_TEST_NATIVE, \
&&OPCODE_TYPE_TEST_SCRIPT, \
&&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_SET_STATIC_VARIABLE, \
&&OPCODE_GET_STATIC_VARIABLE, \
&&OPCODE_ASSIGN, \
&&OPCODE_ASSIGN_NULL, \
&&OPCODE_ASSIGN_TRUE, \
&&OPCODE_ASSIGN_FALSE, \
&&OPCODE_ASSIGN_TYPED_BUILTIN, \
&&OPCODE_ASSIGN_TYPED_ARRAY, \
&&OPCODE_ASSIGN_TYPED_NATIVE, \
&&OPCODE_ASSIGN_TYPED_SCRIPT, \
&&OPCODE_CAST_TO_BUILTIN, \
&&OPCODE_CAST_TO_NATIVE, \
&&OPCODE_CAST_TO_SCRIPT, \
&&OPCODE_CONSTRUCT, \
&&OPCODE_CONSTRUCT_VALIDATED, \
&&OPCODE_CONSTRUCT_ARRAY, \
&&OPCODE_CONSTRUCT_TYPED_ARRAY, \
&&OPCODE_CONSTRUCT_DICTIONARY, \
&&OPCODE_CALL, \
&&OPCODE_CALL_RETURN, \
&&OPCODE_CALL_ASYNC, \
&&OPCODE_CALL_UTILITY, \
&&OPCODE_CALL_UTILITY_VALIDATED, \
&&OPCODE_CALL_GDSCRIPT_UTILITY, \
&&OPCODE_CALL_BUILTIN_TYPE_VALIDATED, \
&&OPCODE_CALL_SELF_BASE, \
&&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \
&&OPCODE_CALL_BUILTIN_STATIC, \
&&OPCODE_CALL_NATIVE_STATIC, \
&&OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN, \
&&OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN, \
&&OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN, \
&&OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN, \
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
&&OPCODE_CREATE_LAMBDA, \
&&OPCODE_CREATE_SELF_LAMBDA, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
&&OPCODE_JUMP_TO_DEF_ARGUMENT, \
&&OPCODE_JUMP_IF_SHARED, \
&&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, \
&&OPCODE_ITERATE_BEGIN_VECTOR2, \
&&OPCODE_ITERATE_BEGIN_VECTOR2I, \
&&OPCODE_ITERATE_BEGIN_VECTOR3, \
&&OPCODE_ITERATE_BEGIN_VECTOR3I, \
&&OPCODE_ITERATE_BEGIN_STRING, \
&&OPCODE_ITERATE_BEGIN_DICTIONARY, \
&&OPCODE_ITERATE_BEGIN_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_BYTE_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_INT32_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_INT64_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT32_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_FLOAT64_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_STRING_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR2_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_BEGIN_PACKED_COLOR_ARRAY, \
2024-04-08 07:51:34 -07:00
&&OPCODE_ITERATE_BEGIN_PACKED_VECTOR4_ARRAY, \
2024-04-25 21:05:53 -03:00
&&OPCODE_ITERATE_BEGIN_OBJECT, \
&&OPCODE_ITERATE, \
&&OPCODE_ITERATE_INT, \
&&OPCODE_ITERATE_FLOAT, \
&&OPCODE_ITERATE_VECTOR2, \
&&OPCODE_ITERATE_VECTOR2I, \
&&OPCODE_ITERATE_VECTOR3, \
&&OPCODE_ITERATE_VECTOR3I, \
&&OPCODE_ITERATE_STRING, \
&&OPCODE_ITERATE_DICTIONARY, \
&&OPCODE_ITERATE_ARRAY, \
&&OPCODE_ITERATE_PACKED_BYTE_ARRAY, \
&&OPCODE_ITERATE_PACKED_INT32_ARRAY, \
&&OPCODE_ITERATE_PACKED_INT64_ARRAY, \
&&OPCODE_ITERATE_PACKED_FLOAT32_ARRAY, \
&&OPCODE_ITERATE_PACKED_FLOAT64_ARRAY, \
&&OPCODE_ITERATE_PACKED_STRING_ARRAY, \
&&OPCODE_ITERATE_PACKED_VECTOR2_ARRAY, \
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
2024-04-08 07:51:34 -07:00
&&OPCODE_ITERATE_PACKED_VECTOR4_ARRAY, \
2024-04-25 21:05:53 -03:00
&&OPCODE_ITERATE_OBJECT, \
&&OPCODE_STORE_GLOBAL, \
&&OPCODE_STORE_NAMED_GLOBAL, \
&&OPCODE_TYPE_ADJUST_BOOL, \
&&OPCODE_TYPE_ADJUST_INT, \
&&OPCODE_TYPE_ADJUST_FLOAT, \
&&OPCODE_TYPE_ADJUST_STRING, \
&&OPCODE_TYPE_ADJUST_VECTOR2, \
&&OPCODE_TYPE_ADJUST_VECTOR2I, \
&&OPCODE_TYPE_ADJUST_RECT2, \
&&OPCODE_TYPE_ADJUST_RECT2I, \
&&OPCODE_TYPE_ADJUST_VECTOR3, \
&&OPCODE_TYPE_ADJUST_VECTOR3I, \
&&OPCODE_TYPE_ADJUST_TRANSFORM2D, \
&&OPCODE_TYPE_ADJUST_VECTOR4, \
&&OPCODE_TYPE_ADJUST_VECTOR4I, \
&&OPCODE_TYPE_ADJUST_PLANE, \
&&OPCODE_TYPE_ADJUST_QUATERNION, \
&&OPCODE_TYPE_ADJUST_AABB, \
&&OPCODE_TYPE_ADJUST_BASIS, \
&&OPCODE_TYPE_ADJUST_TRANSFORM3D, \
&&OPCODE_TYPE_ADJUST_PROJECTION, \
&&OPCODE_TYPE_ADJUST_COLOR, \
&&OPCODE_TYPE_ADJUST_STRING_NAME, \
&&OPCODE_TYPE_ADJUST_NODE_PATH, \
&&OPCODE_TYPE_ADJUST_RID, \
&&OPCODE_TYPE_ADJUST_OBJECT, \
&&OPCODE_TYPE_ADJUST_CALLABLE, \
&&OPCODE_TYPE_ADJUST_SIGNAL, \
&&OPCODE_TYPE_ADJUST_DICTIONARY, \
&&OPCODE_TYPE_ADJUST_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_BYTE_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_INT32_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_INT64_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_FLOAT32_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_FLOAT64_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_STRING_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR2_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR3_ARRAY, \
&&OPCODE_TYPE_ADJUST_PACKED_COLOR_ARRAY, \
2024-04-08 07:51:34 -07:00
&&OPCODE_TYPE_ADJUST_PACKED_VECTOR4_ARRAY, \
2024-04-25 21:05:53 -03:00
&&OPCODE_ASSERT, \
&&OPCODE_BREAKPOINT, \
&&OPCODE_LINE, \
&&OPCODE_END \
}; \
2020-11-12 10:14:48 -03:00
static_assert((sizeof(switch_table_ops) / sizeof(switch_table_ops[0]) == (OPCODE_END + 1)), "Opcodes in jump table aren't the same as opcodes in enum.");
# define OPCODE(m_op) \
m_op:
2023-01-02 15:29:44 +01:00
# define OPCODE_WHILE(m_test)
2020-11-12 10:14:48 -03:00
# define OPCODES_END \
OPSEXIT:
# define OPCODES_OUT \
OPSOUT:
2020-11-13 10:31:14 -03:00
# define OPCODE_SWITCH(m_test) goto *switch_table_ops[m_test];
2023-01-02 15:29:44 +01:00
# ifdef DEBUG_ENABLED
# define DISPATCH_OPCODE \
last_opcode = _code_ptr[ip]; \
goto *switch_table_ops[last_opcode]
# else
# define DISPATCH_OPCODE goto *switch_table_ops[_code_ptr[ip]]
# endif
2020-11-12 10:14:48 -03:00
# define OPCODE_BREAK goto OPSEXIT
# define OPCODE_OUT goto OPSOUT
# else
# define OPCODES_TABLE
# define OPCODE(m_op) case m_op:
# define OPCODE_WHILE(m_test) while (m_test)
# define OPCODES_END
# define OPCODES_OUT
# define DISPATCH_OPCODE continue
2023-08-31 18:38:47 +02:00
# ifdef _MSC_VER
# define OPCODE_SWITCH(m_test) \
__assume(m_test <= OPCODE_END); \
switch (m_test)
# else
2020-11-12 10:14:48 -03:00
# define OPCODE_SWITCH(m_test) switch (m_test)
2023-08-31 18:38:47 +02:00
# endif
2020-11-12 10:14:48 -03:00
# define OPCODE_BREAK break
# define OPCODE_OUT break
# endif
2020-11-17 10:44:52 -03:00
// Helpers for VariantInternal methods in macros.
# define OP_GET_BOOL get_bool
# define OP_GET_INT get_int
# define OP_GET_FLOAT get_float
# define OP_GET_VECTOR2 get_vector2
# define OP_GET_VECTOR2I get_vector2i
# define OP_GET_VECTOR3 get_vector3
# define OP_GET_VECTOR3I get_vector3i
# define OP_GET_RECT2 get_rect2
2022-07-20 01:11:13 +02:00
# define OP_GET_VECTOR4 get_vector4
# define OP_GET_VECTOR4I get_vector4i
2020-11-17 10:44:52 -03:00
# define OP_GET_RECT2I get_rect2i
2021-01-20 07:02:02 +00:00
# define OP_GET_QUATERNION get_quaternion
2020-11-17 10:44:52 -03:00
# define OP_GET_COLOR get_color
# define OP_GET_STRING get_string
# define OP_GET_STRING_NAME get_string_name
# define OP_GET_NODE_PATH get_node_path
# define OP_GET_CALLABLE get_callable
# define OP_GET_SIGNAL get_signal
# define OP_GET_ARRAY get_array
# define OP_GET_DICTIONARY get_dictionary
# define OP_GET_PACKED_BYTE_ARRAY get_byte_array
# define OP_GET_PACKED_INT32_ARRAY get_int32_array
# define OP_GET_PACKED_INT64_ARRAY get_int64_array
# define OP_GET_PACKED_FLOAT32_ARRAY get_float32_array
# define OP_GET_PACKED_FLOAT64_ARRAY get_float64_array
# define OP_GET_PACKED_STRING_ARRAY get_string_array
# define OP_GET_PACKED_VECTOR2_ARRAY get_vector2_array
# define OP_GET_PACKED_VECTOR3_ARRAY get_vector3_array
# define OP_GET_PACKED_COLOR_ARRAY get_color_array
2024-04-08 07:51:34 -07:00
# define OP_GET_PACKED_VECTOR4_ARRAY get_vector4_array
2021-04-28 03:36:08 -04:00
# define OP_GET_TRANSFORM3D get_transform
2020-11-17 10:44:52 -03:00
# define OP_GET_TRANSFORM2D get_transform2d
2022-07-20 01:11:13 +02:00
# define OP_GET_PROJECTION get_projection
2020-11-17 10:44:52 -03:00
# define OP_GET_PLANE get_plane
# define OP_GET_AABB get_aabb
# define OP_GET_BASIS get_basis
# define OP_GET_RID get_rid
2021-10-20 19:09:43 +02:00
# define METHOD_CALL_ON_NULL_VALUE_ERROR(method_pointer) "Cannot call method '" + (method_pointer)->get_name() + "' on a null value."
# define METHOD_CALL_ON_FREED_INSTANCE_ERROR(method_pointer) "Cannot call method '" + (method_pointer)->get_name() + "' on a previously freed instance."
2020-11-12 10:14:48 -03:00
Variant GDScriptFunction : : call ( GDScriptInstance * p_instance , const Variant * * p_args , int p_argcount , Callable : : CallError & r_err , CallState * p_state ) {
OPCODES_TABLE ;
if ( ! _code_ptr ) {
2022-02-17 15:18:43 +00:00
return _get_default_variant_for_data_type ( return_type ) ;
2020-11-12 10:14:48 -03:00
}
r_err . error = Callable : : CallError : : CALL_OK ;
2023-02-07 17:09:40 -03:00
static thread_local int call_depth = 0 ;
if ( unlikely ( + + call_depth > MAX_CALL_DEPTH ) ) {
call_depth - - ;
# ifdef DEBUG_ENABLED
String err_file ;
if ( p_instance & & ObjectDB : : get_instance ( p_instance - > owner_id ) ! = nullptr & & p_instance - > script - > is_valid ( ) & & ! p_instance - > script - > path . is_empty ( ) ) {
err_file = p_instance - > script - > path ;
} else if ( _script ) {
err_file = _script - > path ;
}
if ( err_file . is_empty ( ) ) {
err_file = " <built-in> " ;
}
String err_func = name ;
2023-08-28 19:20:10 +03:00
if ( p_instance & & ObjectDB : : get_instance ( p_instance - > owner_id ) ! = nullptr & & p_instance - > script - > is_valid ( ) & & p_instance - > script - > local_name ! = StringName ( ) ) {
err_func = p_instance - > script - > local_name . operator String ( ) + " . " + err_func ;
2023-02-07 17:09:40 -03:00
}
int err_line = _initial_line ;
const char * err_text = " Stack overflow. Check for infinite recursion in your script. " ;
if ( ! GDScriptLanguage : : get_singleton ( ) - > debug_break ( err_text , false ) ) {
// Debugger break did not happen.
_err_print_error ( err_func . utf8 ( ) . get_data ( ) , err_file . utf8 ( ) . get_data ( ) , err_line , err_text , false , ERR_HANDLER_SCRIPT ) ;
}
# endif
return _get_default_variant_for_data_type ( return_type ) ;
}
2020-11-12 10:14:48 -03:00
Variant retvalue ;
Variant * stack = nullptr ;
2021-04-08 11:55:24 -03:00
Variant * * instruction_args = nullptr ;
2020-11-12 10:14:48 -03:00
int defarg = 0 ;
# ifdef DEBUG_ENABLED
//GDScriptLanguage::get_singleton()->calls++;
# endif
uint32_t alloca_size = 0 ;
GDScript * script ;
int ip = 0 ;
int line = _initial_line ;
if ( p_state ) {
//use existing (supplied) state (awaited)
stack = ( Variant * ) p_state - > stack . ptr ( ) ;
2020-11-13 10:31:14 -03:00
instruction_args = ( Variant * * ) & p_state - > stack . ptr ( ) [ sizeof ( Variant ) * p_state - > stack_size ] ; //ptr() to avoid bounds check
2020-11-12 10:14:48 -03:00
line = p_state - > line ;
ip = p_state - > ip ;
alloca_size = p_state - > stack . size ( ) ;
script = p_state - > script ;
p_instance = p_state - > instance ;
defarg = p_state - > defarg ;
} else {
if ( p_argcount ! = _argument_count ) {
if ( p_argcount > _argument_count ) {
r_err . error = Callable : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ;
2023-09-12 21:55:55 +03:00
r_err . expected = _argument_count ;
2023-02-07 17:09:40 -03:00
call_depth - - ;
2022-02-17 15:18:43 +00:00
return _get_default_variant_for_data_type ( return_type ) ;
2020-11-12 10:14:48 -03:00
} else if ( p_argcount < _argument_count - _default_arg_count ) {
r_err . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2023-09-12 21:55:55 +03:00
r_err . expected = _argument_count - _default_arg_count ;
2023-02-07 17:09:40 -03:00
call_depth - - ;
2022-02-17 15:18:43 +00:00
return _get_default_variant_for_data_type ( return_type ) ;
2020-11-12 10:14:48 -03:00
} else {
defarg = _argument_count - p_argcount ;
}
}
2021-04-08 11:55:24 -03:00
// Add 3 here for self, class, and nil.
alloca_size = sizeof ( Variant * ) * 3 + sizeof ( Variant * ) * _instruction_args_size + sizeof ( Variant ) * _stack_size ;
2020-11-12 10:14:48 -03:00
2021-04-08 11:55:24 -03:00
uint8_t * aptr = ( uint8_t * ) alloca ( alloca_size ) ;
stack = ( Variant * ) aptr ;
2020-11-12 10:14:48 -03:00
2021-04-08 11:55:24 -03:00
for ( int i = 0 ; i < p_argcount ; i + + ) {
if ( ! argument_types [ i ] . has_type ) {
memnew_placement ( & stack [ i + 3 ] , Variant ( * p_args [ i ] ) ) ;
continue ;
2020-11-12 10:14:48 -03:00
}
2022-01-02 05:43:52 +08:00
// If types already match, don't call Variant::construct(). Constructors of some types
// (e.g. packed arrays) do copies, whereas they pass by reference when inside a Variant.
if ( argument_types [ i ] . is_type ( * p_args [ i ] , false ) ) {
memnew_placement ( & stack [ i + 3 ] , Variant ( * p_args [ i ] ) ) ;
continue ;
}
2021-04-08 11:55:24 -03:00
if ( ! argument_types [ i ] . is_type ( * p_args [ i ] , true ) ) {
r_err . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_err . argument = i ;
2022-11-27 09:56:53 +02:00
r_err . expected = argument_types [ i ] . builtin_type ;
2023-02-07 17:09:40 -03:00
call_depth - - ;
2022-02-17 15:18:43 +00:00
return _get_default_variant_for_data_type ( return_type ) ;
2020-11-12 10:14:48 -03:00
}
2021-04-08 11:55:24 -03:00
if ( argument_types [ i ] . kind = = GDScriptDataType : : BUILTIN ) {
2024-07-07 13:43:09 +03:00
if ( argument_types [ i ] . builtin_type = = Variant : : ARRAY & & argument_types [ i ] . has_container_element_type ( 0 ) ) {
const GDScriptDataType & arg_type = argument_types [ i ] . container_element_types [ 0 ] ;
Array array ( p_args [ i ] - > operator Array ( ) , arg_type . builtin_type , arg_type . native_type , arg_type . script_type ) ;
memnew_placement ( & stack [ i + 3 ] , Variant ( array ) ) ;
} else {
Variant variant ;
Variant : : construct ( argument_types [ i ] . builtin_type , variant , & p_args [ i ] , 1 , r_err ) ;
if ( unlikely ( r_err . error ) ) {
r_err . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_err . argument = i ;
r_err . expected = argument_types [ i ] . builtin_type ;
call_depth - - ;
return _get_default_variant_for_data_type ( return_type ) ;
}
memnew_placement ( & stack [ i + 3 ] , Variant ( variant ) ) ;
}
2021-04-08 11:55:24 -03:00
} else {
memnew_placement ( & stack [ i + 3 ] , Variant ( * p_args [ i ] ) ) ;
}
}
for ( int i = p_argcount + 3 ; i < _stack_size ; i + + ) {
memnew_placement ( & stack [ i ] , Variant ) ;
}
2020-11-12 10:14:48 -03:00
2021-04-08 11:55:24 -03:00
if ( _instruction_args_size ) {
instruction_args = ( Variant * * ) & aptr [ sizeof ( Variant ) * _stack_size ] ;
2020-11-12 10:14:48 -03:00
} else {
2020-11-13 10:31:14 -03:00
instruction_args = nullptr ;
2020-11-12 10:14:48 -03:00
}
2022-05-13 14:03:48 -03:00
for ( const KeyValue < int , Variant : : Type > & E : temporary_slots ) {
type_init_function_table [ E . value ] ( & stack [ E . key ] ) ;
2020-11-12 10:14:48 -03:00
}
}
2022-05-13 14:03:48 -03:00
if ( p_instance ) {
memnew_placement ( & stack [ ADDR_STACK_SELF ] , Variant ( p_instance - > owner ) ) ;
script = p_instance - > script . ptr ( ) ;
} else {
memnew_placement ( & stack [ ADDR_STACK_SELF ] , Variant ) ;
script = _script ;
2021-05-17 10:59:43 -03:00
}
2022-05-13 14:03:48 -03:00
memnew_placement ( & stack [ ADDR_STACK_CLASS ] , Variant ( script ) ) ;
memnew_placement ( & stack [ ADDR_STACK_NIL ] , Variant ) ;
2021-05-17 10:59:43 -03:00
2020-11-12 10:14:48 -03:00
String err_text ;
# ifdef DEBUG_ENABLED
if ( EngineDebugger : : is_active ( ) ) {
GDScriptLanguage : : get_singleton ( ) - > enter_function ( p_instance , this , stack , & ip , & line ) ;
}
# define GD_ERR_BREAK(m_cond) \
{ \
if (unlikely(m_cond)) { \
_err_print_error(FUNCTION_STR, __FILE__, __LINE__, "Condition ' " _STR(m_cond) " ' is true. Breaking..:"); \
OPCODE_BREAK; \
} \
}
# define CHECK_SPACE(m_space) \
GD_ERR_BREAK((ip + m_space) > _code_size)
2023-01-02 15:29:44 +01:00
# define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
{ \
int address = _code_ptr[ip + 1 + (m_code_ofs)]; \
int address_type = (address & ADDR_TYPE_MASK) >> ADDR_BITS; \
if (unlikely(address_type < 0 || address_type >= ADDR_TYPE_MAX)) { \
err_text = "Bad address type."; \
OPCODE_BREAK; \
} \
int address_index = address & ADDR_MASK; \
if (unlikely(address_index < 0 || address_index >= variant_address_limits[address_type])) { \
if (address_type == ADDR_TYPE_MEMBER && !p_instance) { \
err_text = "Cannot access member without instance."; \
} else { \
err_text = "Bad address index."; \
} \
OPCODE_BREAK; \
} \
m_v = &variant_addresses[address_type][address_index]; \
if (unlikely(!m_v)) \
OPCODE_BREAK; \
}
2020-11-12 10:14:48 -03:00
# else
# define GD_ERR_BREAK(m_cond)
# define CHECK_SPACE(m_space)
2023-01-02 15:29:44 +01:00
# define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant *m_v; \
{ \
int address = _code_ptr[ip + 1 + (m_code_ofs)]; \
m_v = &variant_addresses[(address & ADDR_TYPE_MASK) >> ADDR_BITS][address & ADDR_MASK]; \
if (unlikely(!m_v)) \
OPCODE_BREAK; \
}
2020-11-12 10:14:48 -03:00
# endif
2023-01-02 15:29:44 +01:00
# define LOAD_INSTRUCTION_ARGS \
int instr_arg_count = _code_ptr[ip + 1]; \
for (int i = 0; i < instr_arg_count; i++) { \
GET_VARIANT_PTR(v, i + 1); \
instruction_args[i] = v; \
} \
ip += 1; // Offset to skip instruction argcount.
2020-11-13 10:31:14 -03:00
# define GET_INSTRUCTION_ARG(m_v, m_idx) \
Variant *m_v = instruction_args[m_idx]
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
uint64_t function_start_time = 0 ;
uint64_t function_call_time = 0 ;
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
function_start_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
function_call_time = 0 ;
2023-04-29 17:20:38 +02:00
profile . call_count . increment ( ) ;
profile . frame_call_count . increment ( ) ;
2020-11-12 10:14:48 -03:00
}
bool exit_ok = false ;
bool awaited = false ;
2024-01-03 01:14:50 +01:00
int variant_address_limits [ ADDR_TYPE_MAX ] = { _stack_size , _constant_count , p_instance ? ( int ) p_instance - > members . size ( ) : 0 } ;
2023-01-02 15:29:44 +01:00
# endif
2023-05-16 13:03:53 +03:00
Variant * variant_addresses [ ADDR_TYPE_MAX ] = { stack , _constants_ptr , p_instance ? p_instance - > members . ptrw ( ) : nullptr } ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
OPCODE_WHILE ( ip < _code_size ) {
2023-01-02 15:29:44 +01:00
int last_opcode = _code_ptr [ ip ] ;
2020-11-12 10:14:48 -03:00
# else
OPCODE_WHILE ( true ) {
# endif
2023-01-02 15:29:44 +01:00
OPCODE_SWITCH ( _code_ptr [ ip ] ) {
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_OPERATOR ) {
2023-07-28 13:08:21 -03:00
constexpr int _pointer_size = sizeof ( Variant : : ValidatedOperatorEvaluator ) / sizeof ( * _code_ptr ) ;
CHECK_SPACE ( 7 + _pointer_size ) ;
2020-11-12 10:14:48 -03:00
bool valid ;
2020-11-13 10:31:14 -03:00
Variant : : Operator op = ( Variant : : Operator ) _code_ptr [ ip + 4 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( op > = Variant : : OP_MAX ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( a , 0 ) ;
GET_VARIANT_PTR ( b , 1 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
2023-07-28 13:08:21 -03:00
// Compute signatures (types of operands) so it can be optimized when matching.
uint32_t op_signature = _code_ptr [ ip + 5 ] ;
uint32_t actual_signature = ( a - > get_type ( ) < < 8 ) | ( b - > get_type ( ) ) ;
2020-11-12 10:14:48 -03:00
2023-10-18 14:12:51 -03:00
# ifdef DEBUG_ENABLED
if ( op = = Variant : : OP_DIVIDE | | op = = Variant : : OP_MODULE ) {
// Don't optimize division and modulo since there's not check for division by zero with validated calls.
op_signature = 0xFFFF ;
_code_ptr [ ip + 5 ] = op_signature ;
}
# endif
2023-07-28 13:08:21 -03:00
// Check if this is the first run. If so, store the current signature for the optimized path.
if ( unlikely ( op_signature = = 0 ) ) {
static Mutex initializer_mutex ;
initializer_mutex . lock ( ) ;
Variant : : Type a_type = ( Variant : : Type ) ( ( actual_signature > > 8 ) & 0xFF ) ;
Variant : : Type b_type = ( Variant : : Type ) ( actual_signature & 0xFF ) ;
2020-11-12 10:14:48 -03:00
2023-07-28 13:08:21 -03:00
Variant : : ValidatedOperatorEvaluator op_func = Variant : : get_validated_operator_evaluator ( op , a_type , b_type ) ;
if ( unlikely ( ! op_func ) ) {
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
err_text = " Invalid operands ' " + Variant : : get_type_name ( a - > get_type ( ) ) + " ' and ' " + Variant : : get_type_name ( b - > get_type ( ) ) + " ' in operator ' " + Variant : : get_operator_name ( op ) + " '. " ;
# endif
2023-07-28 13:08:21 -03:00
initializer_mutex . unlock ( ) ;
OPCODE_BREAK ;
} else {
Variant : : Type ret_type = Variant : : get_operator_return_type ( op , a_type , b_type ) ;
VariantInternal : : initialize ( dst , ret_type ) ;
op_func ( a , b , dst ) ;
// Check again in case another thread already set it.
if ( _code_ptr [ ip + 5 ] = = 0 ) {
_code_ptr [ ip + 5 ] = actual_signature ;
_code_ptr [ ip + 6 ] = static_cast < int > ( ret_type ) ;
Variant : : ValidatedOperatorEvaluator * tmp = reinterpret_cast < Variant : : ValidatedOperatorEvaluator * > ( & _code_ptr [ ip + 7 ] ) ;
* tmp = op_func ;
}
}
initializer_mutex . unlock ( ) ;
} else if ( likely ( op_signature = = actual_signature ) ) {
// If the signature matches, we can use the optimized path.
Variant : : Type ret_type = static_cast < Variant : : Type > ( _code_ptr [ ip + 6 ] ) ;
Variant : : ValidatedOperatorEvaluator op_func = * reinterpret_cast < Variant : : ValidatedOperatorEvaluator * > ( & _code_ptr [ ip + 7 ] ) ;
// Make sure the return value has the correct type.
VariantInternal : : initialize ( dst , ret_type ) ;
op_func ( a , b , dst ) ;
} else {
// If the signature doesn't match, we have to use the slow path.
# ifdef DEBUG_ENABLED
Variant ret ;
Variant : : evaluate ( op , * a , * b , ret , valid ) ;
# else
Variant : : evaluate ( op , * a , * b , * dst , valid ) ;
# endif
# ifdef DEBUG_ENABLED
if ( ! valid ) {
if ( ret . get_type ( ) = = Variant : : STRING ) {
//return a string when invalid with the error
err_text = ret ;
err_text + = " in operator ' " + Variant : : get_operator_name ( op ) + " '. " ;
} else {
err_text = " Invalid operands ' " + Variant : : get_type_name ( a - > get_type ( ) ) + " ' and ' " + Variant : : get_type_name ( b - > get_type ( ) ) + " ' in operator ' " + Variant : : get_operator_name ( op ) + " '. " ;
}
OPCODE_BREAK ;
}
* dst = ret ;
# endif
}
ip + = 7 + _pointer_size ;
2020-11-12 10:14:48 -03:00
}
DISPATCH_OPCODE ;
2020-11-13 16:47:45 -03:00
OPCODE ( OPCODE_OPERATOR_VALIDATED ) {
CHECK_SPACE ( 5 ) ;
int operator_idx = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( operator_idx < 0 | | operator_idx > = _operator_funcs_count ) ;
Variant : : ValidatedOperatorEvaluator operator_func = _operator_funcs_ptr [ operator_idx ] ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( a , 0 ) ;
GET_VARIANT_PTR ( b , 1 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
2020-11-13 16:47:45 -03:00
operator_func ( a , b , dst ) ;
ip + = 5 ;
}
DISPATCH_OPCODE ;
2023-02-17 01:16:24 +02:00
OPCODE ( OPCODE_TYPE_TEST_BUILTIN ) {
2020-11-12 10:14:48 -03:00
CHECK_SPACE ( 4 ) ;
2023-02-17 01:16:24 +02:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( value , 1 ) ;
2020-11-12 10:14:48 -03:00
2023-02-17 01:16:24 +02:00
Variant : : Type builtin_type = ( Variant : : Type ) _code_ptr [ ip + 3 ] ;
GD_ERR_BREAK ( builtin_type < 0 | | builtin_type > = Variant : : VARIANT_MAX ) ;
2020-11-12 10:14:48 -03:00
2023-02-17 01:16:24 +02:00
* dst = value - > get_type ( ) = = builtin_type ;
2020-11-12 10:14:48 -03:00
ip + = 4 ;
}
DISPATCH_OPCODE ;
2023-02-17 01:16:24 +02:00
OPCODE ( OPCODE_TYPE_TEST_ARRAY ) {
CHECK_SPACE ( 6 ) ;
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( value , 1 ) ;
GET_VARIANT_PTR ( script_type , 2 ) ;
Variant : : Type builtin_type = ( Variant : : Type ) _code_ptr [ ip + 4 ] ;
int native_type_idx = _code_ptr [ ip + 5 ] ;
GD_ERR_BREAK ( native_type_idx < 0 | | native_type_idx > = _global_names_count ) ;
const StringName native_type = _global_names_ptr [ native_type_idx ] ;
bool result = false ;
if ( value - > get_type ( ) = = Variant : : ARRAY ) {
Array * array = VariantInternal : : get_array ( value ) ;
2023-04-06 06:12:32 +03:00
result = array - > get_typed_builtin ( ) = = ( ( uint32_t ) builtin_type ) & & array - > get_typed_class_name ( ) = = native_type & & array - > get_typed_script ( ) = = * script_type ;
2023-02-17 01:16:24 +02:00
}
* dst = result ;
ip + = 6 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_TYPE_TEST_NATIVE ) {
2020-11-12 10:14:48 -03:00
CHECK_SPACE ( 4 ) ;
2023-02-17 01:16:24 +02:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( value , 1 ) ;
2020-11-12 10:14:48 -03:00
2023-02-17 01:16:24 +02:00
int native_type_idx = _code_ptr [ ip + 3 ] ;
GD_ERR_BREAK ( native_type_idx < 0 | | native_type_idx > = _global_names_count ) ;
const StringName native_type = _global_names_ptr [ native_type_idx ] ;
2020-11-12 10:14:48 -03:00
2023-02-17 01:16:24 +02:00
bool was_freed = false ;
Object * object = value - > get_validated_object_with_check ( was_freed ) ;
if ( was_freed ) {
err_text = " Left operand of 'is' is a previously freed instance. " ;
OPCODE_BREAK ;
}
* dst = object & & ClassDB : : is_parent_class ( object - > get_class_name ( ) , native_type ) ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_TYPE_TEST_SCRIPT ) {
CHECK_SPACE ( 4 ) ;
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( value , 1 ) ;
GET_VARIANT_PTR ( type , 2 ) ;
Script * script_type = Object : : cast_to < Script > ( type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! script_type ) ;
bool was_freed = false ;
Object * object = value - > get_validated_object_with_check ( was_freed ) ;
if ( was_freed ) {
err_text = " Left operand of 'is' is a previously freed instance. " ;
OPCODE_BREAK ;
}
bool result = false ;
if ( object & & object - > get_script_instance ( ) ) {
Script * script_ptr = object - > get_script_instance ( ) - > get_script ( ) . ptr ( ) ;
while ( script_ptr ) {
if ( script_ptr = = script_type ) {
result = true ;
break ;
}
script_ptr = script_ptr - > get_base_script ( ) . ptr ( ) ;
}
}
* dst = result ;
2020-11-12 10:14:48 -03:00
ip + = 4 ;
}
DISPATCH_OPCODE ;
2020-11-16 12:59:53 -03:00
OPCODE ( OPCODE_SET_KEYED ) {
2020-11-12 10:14:48 -03:00
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( index , 1 ) ;
GET_VARIANT_PTR ( value , 2 ) ;
2020-11-12 10:14:48 -03:00
bool valid ;
2022-10-05 20:49:35 +02:00
# ifdef DEBUG_ENABLED
Variant : : VariantSetError err_code ;
dst - > set ( * index , * value , & valid , & err_code ) ;
# else
2020-11-12 10:14:48 -03:00
dst - > set ( * index , * value , & valid ) ;
2022-10-05 20:49:35 +02:00
# endif
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
if ( ! valid ) {
2024-03-18 14:42:42 +01:00
if ( dst - > is_read_only ( ) ) {
err_text = " Invalid assignment on read-only value (on base: ' " + _get_var_type ( dst ) + " '). " ;
2020-11-12 10:14:48 -03:00
} else {
2024-03-18 14:42:42 +01:00
Object * obj = dst - > get_validated_object ( ) ;
String v = index - > operator String ( ) ;
bool read_only_property = false ;
if ( obj ) {
read_only_property = ClassDB : : has_property ( obj - > get_class_name ( ) , v ) & & ( ClassDB : : get_property_setter ( obj - > get_class_name ( ) , v ) = = StringName ( ) ) ;
2023-01-30 14:50:08 -03:00
}
2024-03-18 14:42:42 +01:00
if ( read_only_property ) {
err_text = vformat ( R " (Cannot set value into property " % s " (on base " % s " ) because it is read-only.) " , v , _get_var_type ( dst ) ) ;
} else {
if ( ! v . is_empty ( ) ) {
v = " ' " + v + " ' " ;
} else {
v = " of type ' " + _get_var_type ( index ) + " ' " ;
}
err_text = " Invalid assignment of property or key " + v + " with value of type ' " + _get_var_type ( value ) + " ' on a base object of type ' " + _get_var_type ( dst ) + " '. " ;
if ( err_code = = Variant : : VariantSetError : : SET_INDEXED_ERR ) {
err_text = " Invalid assignment of index " + v + " (on base: ' " + _get_var_type ( dst ) + " ') with value of type ' " + _get_var_type ( value ) + " '. " ;
}
2022-10-05 20:49:35 +02:00
}
2020-11-12 10:14:48 -03:00
}
OPCODE_BREAK ;
}
# endif
ip + = 4 ;
}
DISPATCH_OPCODE ;
2020-11-16 12:59:53 -03:00
OPCODE ( OPCODE_SET_KEYED_VALIDATED ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( index , 1 ) ;
GET_VARIANT_PTR ( value , 2 ) ;
2020-11-16 12:59:53 -03:00
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 ;
2020-12-10 17:12:02 -03:00
setter ( dst , index , value , & valid ) ;
2020-11-16 12:59:53 -03:00
# ifdef DEBUG_ENABLED
if ( ! valid ) {
2024-03-18 14:42:42 +01:00
if ( dst - > is_read_only ( ) ) {
err_text = " Invalid assignment on read-only value (on base: ' " + _get_var_type ( dst ) + " '). " ;
2020-11-16 12:59:53 -03:00
} else {
2024-03-18 14:42:42 +01:00
String v = index - > operator String ( ) ;
if ( ! v . is_empty ( ) ) {
v = " ' " + v + " ' " ;
} else {
v = " of type ' " + _get_var_type ( index ) + " ' " ;
}
err_text = " Invalid assignment of property or key " + v + " with value of type ' " + _get_var_type ( value ) + " ' on a base object of type ' " + _get_var_type ( dst ) + " '. " ;
2020-11-16 12:59:53 -03:00
}
OPCODE_BREAK ;
}
# endif
ip + = 5 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_SET_INDEXED_VALIDATED ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( index , 1 ) ;
GET_VARIANT_PTR ( value , 2 ) ;
2020-11-16 12:59:53 -03:00
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 ;
2020-12-10 17:12:02 -03:00
setter ( dst , int_index , value , & oob ) ;
2020-11-16 12:59:53 -03:00
# ifdef DEBUG_ENABLED
if ( oob ) {
2024-03-18 14:42:42 +01:00
if ( dst - > is_read_only ( ) ) {
err_text = " Invalid assignment on read-only value (on base: ' " + _get_var_type ( dst ) + " '). " ;
2020-11-16 12:59:53 -03:00
} else {
2024-03-18 14:42:42 +01:00
String v = index - > operator String ( ) ;
if ( ! v . is_empty ( ) ) {
v = " ' " + v + " ' " ;
} else {
v = " of type ' " + _get_var_type ( index ) + " ' " ;
}
err_text = " Out of bounds set index " + v + " (on base: ' " + _get_var_type ( dst ) + " ') " ;
2020-11-16 12:59:53 -03:00
}
OPCODE_BREAK ;
}
# endif
ip + = 5 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_GET_KEYED ) {
2020-11-12 10:14:48 -03:00
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( index , 1 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
2020-11-12 10:14:48 -03:00
bool valid ;
# ifdef DEBUG_ENABLED
2020-11-16 12:59:53 -03:00
// Allow better error message in cases where src and dst are the same stack position.
2022-10-05 20:49:35 +02:00
Variant : : VariantGetError err_code ;
Variant ret = src - > get ( * index , & valid , & err_code ) ;
2020-11-12 10:14:48 -03:00
# else
* dst = src - > get ( * index , & valid ) ;
# endif
# ifdef DEBUG_ENABLED
if ( ! valid ) {
String v = index - > operator String ( ) ;
2021-12-09 03:42:46 -06:00
if ( ! v . is_empty ( ) ) {
2020-11-12 10:14:48 -03:00
v = " ' " + v + " ' " ;
} else {
v = " of type ' " + _get_var_type ( index ) + " ' " ;
}
2022-10-05 20:49:35 +02:00
err_text = " Invalid access to property or key " + v + " on a base object of type ' " + _get_var_type ( src ) + " '. " ;
if ( err_code = = Variant : : VariantGetError : : GET_INDEXED_ERR ) {
err_text = " Invalid access of index " + v + " on a base object of type: ' " + _get_var_type ( src ) + " '. " ;
}
2020-11-12 10:14:48 -03:00
OPCODE_BREAK ;
}
* dst = ret ;
# endif
ip + = 4 ;
}
DISPATCH_OPCODE ;
2020-11-16 12:59:53 -03:00
OPCODE ( OPCODE_GET_KEYED_VALIDATED ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( key , 1 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
2020-11-16 12:59:53 -03:00
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 ;
2020-12-10 17:12:02 -03:00
getter ( src , key , & ret , & valid ) ;
2020-11-16 12:59:53 -03:00
# else
2020-12-10 17:12:02 -03:00
getter ( src , key , dst , & valid ) ;
2020-11-16 12:59:53 -03:00
# endif
# ifdef DEBUG_ENABLED
if ( ! valid ) {
String v = key - > operator String ( ) ;
2021-12-09 03:42:46 -06:00
if ( ! v . is_empty ( ) ) {
2020-11-16 12:59:53 -03:00
v = " ' " + v + " ' " ;
} else {
v = " of type ' " + _get_var_type ( key ) + " ' " ;
}
2022-10-05 20:49:35 +02:00
err_text = " Invalid access to property or key " + v + " on a base object of type ' " + _get_var_type ( src ) + " '. " ;
2020-11-16 12:59:53 -03:00
OPCODE_BREAK ;
}
* dst = ret ;
# endif
ip + = 5 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_GET_INDEXED_VALIDATED ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( index , 1 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
2020-11-16 12:59:53 -03:00
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 ;
2020-12-10 17:12:02 -03:00
getter ( src , int_index , dst , & oob ) ;
2020-11-16 12:59:53 -03:00
# ifdef DEBUG_ENABLED
if ( oob ) {
String v = index - > operator String ( ) ;
2021-12-09 03:42:46 -06:00
if ( ! v . is_empty ( ) ) {
2020-11-16 12:59:53 -03:00
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 ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_SET_NAMED ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( value , 1 ) ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
int indexname = _code_ptr [ ip + 3 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
const StringName * index = & _global_names_ptr [ indexname ] ;
bool valid ;
dst - > set_named ( * index , * value , valid ) ;
# ifdef DEBUG_ENABLED
if ( ! valid ) {
2024-03-18 14:42:42 +01:00
if ( dst - > is_read_only ( ) ) {
err_text = " Invalid assignment on read-only value (on base: ' " + _get_var_type ( dst ) + " '). " ;
2023-01-30 14:50:08 -03:00
} else {
2024-03-18 14:42:42 +01:00
Object * obj = dst - > get_validated_object ( ) ;
bool read_only_property = false ;
if ( obj ) {
read_only_property = ClassDB : : has_property ( obj - > get_class_name ( ) , * index ) & & ( ClassDB : : get_property_setter ( obj - > get_class_name ( ) , * index ) = = StringName ( ) ) ;
}
if ( read_only_property ) {
err_text = vformat ( R " (Cannot set value into property " % s " (on base " % s " ) because it is read-only.) " , String ( * index ) , _get_var_type ( dst ) ) ;
} else {
err_text = " Invalid assignment of property or key ' " + String ( * index ) + " ' with value of type ' " + _get_var_type ( value ) + " ' on a base object of type ' " + _get_var_type ( dst ) + " '. " ;
}
2023-01-30 14:50:08 -03:00
}
2020-11-12 10:14:48 -03:00
OPCODE_BREAK ;
}
# endif
ip + = 4 ;
}
DISPATCH_OPCODE ;
2020-11-16 12:59:53 -03:00
OPCODE ( OPCODE_SET_NAMED_VALIDATED ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( value , 1 ) ;
2020-11-16 12:59:53 -03:00
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 ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_GET_NAMED ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( dst , 1 ) ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
int indexname = _code_ptr [ ip + 3 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
const StringName * index = & _global_names_ptr [ indexname ] ;
bool valid ;
# ifdef DEBUG_ENABLED
//allow better error message in cases where src and dst are the same stack position
Variant ret = src - > get_named ( * index , valid ) ;
# else
* dst = src - > get_named ( * index , valid ) ;
# endif
# ifdef DEBUG_ENABLED
if ( ! valid ) {
2022-10-05 20:49:35 +02:00
err_text = " Invalid access to property or key ' " + index - > operator String ( ) + " ' on a base object of type ' " + _get_var_type ( src ) + " '. " ;
2020-11-12 10:14:48 -03:00
OPCODE_BREAK ;
}
* dst = ret ;
# endif
ip + = 4 ;
}
DISPATCH_OPCODE ;
2020-11-16 12:59:53 -03:00
OPCODE ( OPCODE_GET_NAMED_VALIDATED ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( dst , 1 ) ;
2020-11-16 12:59:53 -03:00
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 ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_SET_MEMBER ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
2020-11-13 10:31:14 -03:00
int indexname = _code_ptr [ ip + 2 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
const StringName * index = & _global_names_ptr [ indexname ] ;
bool valid ;
# ifndef DEBUG_ENABLED
ClassDB : : set_property ( p_instance - > owner , * index , * src , & valid ) ;
# else
bool ok = ClassDB : : set_property ( p_instance - > owner , * index , * src , & valid ) ;
if ( ! ok ) {
err_text = " Internal error setting property: " + String ( * index ) ;
OPCODE_BREAK ;
} else if ( ! valid ) {
err_text = " Error setting property ' " + String ( * index ) + " ' with value of type " + Variant : : get_type_name ( src - > get_type ( ) ) + " . " ;
OPCODE_BREAK ;
}
# endif
ip + = 3 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_GET_MEMBER ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
2020-11-13 10:31:14 -03:00
int indexname = _code_ptr [ ip + 2 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
const StringName * index = & _global_names_ptr [ indexname ] ;
# ifndef DEBUG_ENABLED
ClassDB : : get_property ( p_instance - > owner , * index , * dst ) ;
# else
bool ok = ClassDB : : get_property ( p_instance - > owner , * index , * dst ) ;
if ( ! ok ) {
err_text = " Internal error getting property: " + String ( * index ) ;
OPCODE_BREAK ;
}
# endif
ip + = 3 ;
}
DISPATCH_OPCODE ;
2023-05-16 13:03:53 +03:00
OPCODE ( OPCODE_SET_STATIC_VARIABLE ) {
CHECK_SPACE ( 4 ) ;
GET_VARIANT_PTR ( value , 0 ) ;
GET_VARIANT_PTR ( _class , 1 ) ;
GDScript * gdscript = Object : : cast_to < GDScript > ( _class - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! gdscript ) ;
int index = _code_ptr [ ip + 3 ] ;
GD_ERR_BREAK ( index < 0 | | index > = gdscript - > static_variables . size ( ) ) ;
gdscript - > static_variables . write [ index ] = * value ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_GET_STATIC_VARIABLE ) {
CHECK_SPACE ( 4 ) ;
GET_VARIANT_PTR ( target , 0 ) ;
GET_VARIANT_PTR ( _class , 1 ) ;
GDScript * gdscript = Object : : cast_to < GDScript > ( _class - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! gdscript ) ;
int index = _code_ptr [ ip + 3 ] ;
GD_ERR_BREAK ( index < 0 | | index > = gdscript - > static_variables . size ( ) ) ;
* target = gdscript - > static_variables [ index ] ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_ASSIGN ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( src , 1 ) ;
2020-11-12 10:14:48 -03:00
* dst = * src ;
ip + = 3 ;
}
DISPATCH_OPCODE ;
2024-03-28 21:57:56 +03:00
OPCODE ( OPCODE_ASSIGN_NULL ) {
CHECK_SPACE ( 2 ) ;
GET_VARIANT_PTR ( dst , 0 ) ;
* dst = Variant ( ) ;
ip + = 2 ;
}
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_ASSIGN_TRUE ) {
CHECK_SPACE ( 2 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
2020-11-12 10:14:48 -03:00
* dst = true ;
ip + = 2 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ASSIGN_FALSE ) {
CHECK_SPACE ( 2 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
2020-11-12 10:14:48 -03:00
* dst = false ;
ip + = 2 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ASSIGN_TYPED_BUILTIN ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( src , 1 ) ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
Variant : : Type var_type = ( Variant : : Type ) _code_ptr [ ip + 3 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( var_type < 0 | | var_type > = Variant : : VARIANT_MAX ) ;
if ( src - > get_type ( ) ! = var_type ) {
# ifdef DEBUG_ENABLED
if ( Variant : : can_convert_strict ( src - > get_type ( ) , var_type ) ) {
# endif // DEBUG_ENABLED
Callable : : CallError ce ;
Variant : : construct ( var_type , * dst , const_cast < const Variant * * > ( & src ) , 1 , ce ) ;
} else {
# ifdef DEBUG_ENABLED
err_text = " Trying to assign value of type ' " + Variant : : get_type_name ( src - > get_type ( ) ) +
2021-10-28 15:19:35 +02:00
" ' to a variable of type ' " + Variant : : get_type_name ( var_type ) + " '. " ;
2020-11-12 10:14:48 -03:00
OPCODE_BREAK ;
}
} else {
# endif // DEBUG_ENABLED
* dst = * src ;
}
ip + = 4 ;
}
DISPATCH_OPCODE ;
2021-03-09 12:32:35 -03:00
OPCODE ( OPCODE_ASSIGN_TYPED_ARRAY ) {
2022-11-27 09:56:53 +02:00
CHECK_SPACE ( 6 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( src , 1 ) ;
2021-03-09 12:32:35 -03:00
2022-11-27 09:56:53 +02:00
GET_VARIANT_PTR ( script_type , 2 ) ;
Variant : : Type builtin_type = ( Variant : : Type ) _code_ptr [ ip + 4 ] ;
int native_type_idx = _code_ptr [ ip + 5 ] ;
GD_ERR_BREAK ( native_type_idx < 0 | | native_type_idx > = _global_names_count ) ;
const StringName native_type = _global_names_ptr [ native_type_idx ] ;
2021-03-09 12:32:35 -03:00
if ( src - > get_type ( ) ! = Variant : : ARRAY ) {
# ifdef DEBUG_ENABLED
2022-11-27 09:56:53 +02:00
err_text = vformat ( R " (Trying to assign a value of type " % s " to a variable of type " Array [ % s ] " .) " ,
_get_var_type ( src ) , _get_element_type ( builtin_type , native_type , * script_type ) ) ;
# endif // DEBUG_ENABLED
2021-04-02 10:34:44 -03:00
OPCODE_BREAK ;
2021-03-09 12:32:35 -03:00
}
2022-11-27 09:56:53 +02:00
Array * array = VariantInternal : : get_array ( src ) ;
2023-04-06 06:12:32 +03:00
if ( array - > get_typed_builtin ( ) ! = ( ( uint32_t ) builtin_type ) | | array - > get_typed_class_name ( ) ! = native_type | | array - > get_typed_script ( ) ! = * script_type ) {
2022-11-27 09:56:53 +02:00
# ifdef DEBUG_ENABLED
err_text = vformat ( R " (Trying to assign an array of type " % s " to a variable of type " Array [ % s ] " .) " ,
_get_var_type ( src ) , _get_element_type ( builtin_type , native_type , * script_type ) ) ;
# endif // DEBUG_ENABLED
OPCODE_BREAK ;
}
* dst = * src ;
ip + = 6 ;
2021-03-09 12:32:35 -03:00
}
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_ASSIGN_TYPED_NATIVE ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( src , 1 ) ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( type , 2 ) ;
2020-11-12 10:14:48 -03:00
GDScriptNativeClass * nc = Object : : cast_to < GDScriptNativeClass > ( type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! nc ) ;
if ( src - > get_type ( ) ! = Variant : : OBJECT & & src - > get_type ( ) ! = Variant : : NIL ) {
err_text = " Trying to assign value of type ' " + Variant : : get_type_name ( src - > get_type ( ) ) +
2021-10-28 15:19:35 +02:00
" ' to a variable of type ' " + nc - > get_name ( ) + " '. " ;
2020-11-12 10:14:48 -03:00
OPCODE_BREAK ;
}
2023-02-15 09:42:53 -05:00
2023-02-17 09:25:57 -05:00
if ( src - > get_type ( ) = = Variant : : OBJECT ) {
bool was_freed = false ;
Object * src_obj = src - > get_validated_object_with_check ( was_freed ) ;
if ( ! src_obj & & was_freed ) {
2023-02-15 09:42:53 -05:00
err_text = " Trying to assign invalid previously freed instance. " ;
2023-02-17 09:25:57 -05:00
OPCODE_BREAK ;
2023-02-15 09:42:53 -05:00
}
2020-11-12 10:14:48 -03:00
2023-02-17 09:25:57 -05:00
if ( src_obj & & ! ClassDB : : is_parent_class ( src_obj - > get_class_name ( ) , nc - > get_name ( ) ) ) {
err_text = " Trying to assign value of type ' " + src_obj - > get_class_name ( ) +
" ' to a variable of type ' " + nc - > get_name ( ) + " '. " ;
OPCODE_BREAK ;
}
2020-11-12 10:14:48 -03:00
}
# endif // DEBUG_ENABLED
* dst = * src ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ASSIGN_TYPED_SCRIPT ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
GET_VARIANT_PTR ( src , 1 ) ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( type , 2 ) ;
2020-11-12 10:14:48 -03:00
Script * base_type = Object : : cast_to < Script > ( type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! base_type ) ;
if ( src - > get_type ( ) ! = Variant : : OBJECT & & src - > get_type ( ) ! = Variant : : NIL ) {
err_text = " Trying to assign a non-object value to a variable of type ' " + base_type - > get_path ( ) . get_file ( ) + " '. " ;
OPCODE_BREAK ;
}
2023-02-17 09:25:57 -05:00
if ( src - > get_type ( ) = = Variant : : OBJECT ) {
2023-02-15 09:42:53 -05:00
bool was_freed = false ;
Object * val_obj = src - > get_validated_object_with_check ( was_freed ) ;
2023-02-17 09:25:57 -05:00
if ( ! val_obj & & was_freed ) {
err_text = " Trying to assign invalid previously freed instance. " ;
2023-02-15 09:42:53 -05:00
OPCODE_BREAK ;
}
2023-02-21 15:29:07 -05:00
if ( val_obj ) { // src is not null
ScriptInstance * scr_inst = val_obj - > get_script_instance ( ) ;
if ( ! scr_inst ) {
err_text = " Trying to assign value of type ' " + val_obj - > get_class_name ( ) +
" ' to a variable of type ' " + base_type - > get_path ( ) . get_file ( ) + " '. " ;
OPCODE_BREAK ;
2020-11-12 10:14:48 -03:00
}
2023-02-21 15:29:07 -05:00
Script * src_type = scr_inst - > get_script ( ) . ptr ( ) ;
bool valid = false ;
while ( src_type ) {
if ( src_type = = base_type ) {
valid = true ;
break ;
}
src_type = src_type - > get_base_script ( ) . ptr ( ) ;
}
if ( ! valid ) {
err_text = " Trying to assign value of type ' " + val_obj - > get_script_instance ( ) - > get_script ( ) - > get_path ( ) . get_file ( ) +
" ' to a variable of type ' " + base_type - > get_path ( ) . get_file ( ) + " '. " ;
OPCODE_BREAK ;
}
2020-11-12 10:14:48 -03:00
}
}
# endif // DEBUG_ENABLED
* dst = * src ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CAST_TO_BUILTIN ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( dst , 1 ) ;
2020-11-13 10:31:14 -03:00
Variant : : Type to_type = ( Variant : : Type ) _code_ptr [ ip + 3 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( to_type < 0 | | to_type > = Variant : : VARIANT_MAX ) ;
2021-07-31 11:21:41 +02:00
# ifdef DEBUG_ENABLED
2021-09-27 19:35:26 +02:00
if ( src - > operator Object * ( ) & & ! src - > get_validated_object ( ) ) {
2021-07-31 11:21:41 +02:00
err_text = " Trying to cast a freed object. " ;
OPCODE_BREAK ;
}
# endif
2020-11-12 10:14:48 -03:00
Callable : : CallError err ;
Variant : : construct ( to_type , * dst , ( const Variant * * ) & src , 1 , err ) ;
# ifdef DEBUG_ENABLED
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
err_text = " Invalid cast: could not convert value to ' " + Variant : : get_type_name ( to_type ) + " '. " ;
OPCODE_BREAK ;
}
# endif
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CAST_TO_NATIVE ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( dst , 1 ) ;
GET_VARIANT_PTR ( to_type , 2 ) ;
2020-11-12 10:14:48 -03:00
GDScriptNativeClass * nc = Object : : cast_to < GDScriptNativeClass > ( to_type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! nc ) ;
# ifdef DEBUG_ENABLED
2021-09-27 19:35:26 +02:00
if ( src - > operator Object * ( ) & & ! src - > get_validated_object ( ) ) {
2021-07-31 11:21:41 +02:00
err_text = " Trying to cast a freed object. " ;
OPCODE_BREAK ;
}
2020-11-12 10:14:48 -03:00
if ( src - > get_type ( ) ! = Variant : : OBJECT & & src - > get_type ( ) ! = Variant : : NIL ) {
err_text = " Invalid cast: can't convert a non-object value to an object type. " ;
OPCODE_BREAK ;
}
# endif
Object * src_obj = src - > operator Object * ( ) ;
if ( src_obj & & ! ClassDB : : is_parent_class ( src_obj - > get_class_name ( ) , nc - > get_name ( ) ) ) {
* dst = Variant ( ) ; // invalid cast, assign NULL
} else {
* dst = * src ;
}
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CAST_TO_SCRIPT ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( src , 0 ) ;
GET_VARIANT_PTR ( dst , 1 ) ;
GET_VARIANT_PTR ( to_type , 2 ) ;
2020-11-12 10:14:48 -03:00
Script * base_type = Object : : cast_to < Script > ( to_type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! base_type ) ;
# ifdef DEBUG_ENABLED
2021-09-27 19:35:26 +02:00
if ( src - > operator Object * ( ) & & ! src - > get_validated_object ( ) ) {
2021-07-31 11:21:41 +02:00
err_text = " Trying to cast a freed object. " ;
OPCODE_BREAK ;
}
2020-11-12 10:14:48 -03:00
if ( src - > get_type ( ) ! = Variant : : OBJECT & & src - > get_type ( ) ! = Variant : : NIL ) {
err_text = " Trying to assign a non-object value to a variable of type ' " + base_type - > get_path ( ) . get_file ( ) + " '. " ;
OPCODE_BREAK ;
}
# endif
bool valid = false ;
if ( src - > get_type ( ) ! = Variant : : NIL & & src - > operator Object * ( ) ! = nullptr ) {
ScriptInstance * scr_inst = src - > operator Object * ( ) - > get_script_instance ( ) ;
if ( scr_inst ) {
Script * src_type = src - > operator Object * ( ) - > get_script_instance ( ) - > get_script ( ) . ptr ( ) ;
while ( src_type ) {
if ( src_type = = base_type ) {
valid = true ;
break ;
}
src_type = src_type - > get_base_script ( ) . ptr ( ) ;
}
}
}
if ( valid ) {
* dst = * src ; // Valid cast, copy the source object
} else {
* dst = Variant ( ) ; // invalid cast, assign NULL
}
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CONSTRUCT ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-13 10:31:14 -03:00
CHECK_SPACE ( 2 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
Variant : : Type t = Variant : : Type ( _code_ptr [ ip + 2 ] ) ;
2023-01-02 15:29:44 +01:00
2020-11-13 10:31:14 -03:00
Variant * * argptrs = instruction_args ;
GET_INSTRUCTION_ARG ( dst , argc ) ;
2020-11-12 10:14:48 -03:00
Callable : : CallError err ;
Variant : : construct ( t , * dst , ( const Variant * * ) argptrs , argc , err ) ;
# ifdef DEBUG_ENABLED
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
err_text = _get_call_error ( err , " ' " + Variant : : get_type_name ( t ) + " ' constructor " , ( const Variant * * ) argptrs ) ;
OPCODE_BREAK ;
}
# endif
2020-11-13 10:31:14 -03:00
ip + = 3 ;
2020-11-12 10:14:48 -03:00
}
DISPATCH_OPCODE ;
2020-11-18 11:37:08 -03:00
OPCODE ( OPCODE_CONSTRUCT_VALIDATED ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-18 11:37:08 -03:00
CHECK_SPACE ( 2 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
int constructor_idx = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( constructor_idx < 0 | | constructor_idx > = _constructors_count ) ;
Variant : : ValidatedConstructor constructor = _constructors_ptr [ constructor_idx ] ;
Variant * * argptrs = instruction_args ;
GET_INSTRUCTION_ARG ( dst , argc ) ;
2020-12-10 17:12:02 -03:00
constructor ( dst , ( const Variant * * ) argptrs ) ;
2020-11-18 11:37:08 -03:00
ip + = 3 ;
}
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_CONSTRUCT_ARRAY ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-13 10:31:14 -03:00
CHECK_SPACE ( 1 + instr_arg_count ) ;
ip + = instr_arg_count ;
2020-11-12 10:14:48 -03:00
int argc = _code_ptr [ ip + 1 ] ;
2020-11-13 10:31:14 -03:00
Array array ;
2020-11-12 10:14:48 -03:00
array . resize ( argc ) ;
for ( int i = 0 ; i < argc ; i + + ) {
2020-11-13 10:31:14 -03:00
array [ i ] = * ( instruction_args [ i ] ) ;
2020-11-12 10:14:48 -03:00
}
2020-11-13 10:31:14 -03:00
GET_INSTRUCTION_ARG ( dst , argc ) ;
2021-03-09 12:32:35 -03:00
* dst = Variant ( ) ; // Clear potential previous typed array.
2020-11-12 10:14:48 -03:00
* dst = array ;
2020-11-13 10:31:14 -03:00
ip + = 2 ;
2020-11-12 10:14:48 -03:00
}
DISPATCH_OPCODE ;
2021-03-09 12:32:35 -03:00
OPCODE ( OPCODE_CONSTRUCT_TYPED_ARRAY ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2021-03-09 12:32:35 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GET_INSTRUCTION_ARG ( script_type , argc + 1 ) ;
Variant : : Type builtin_type = ( Variant : : Type ) _code_ptr [ ip + 2 ] ;
int native_type_idx = _code_ptr [ ip + 3 ] ;
GD_ERR_BREAK ( native_type_idx < 0 | | native_type_idx > = _global_names_count ) ;
const StringName native_type = _global_names_ptr [ native_type_idx ] ;
Array array ;
array . resize ( argc ) ;
for ( int i = 0 ; i < argc ; i + + ) {
array [ i ] = * ( instruction_args [ i ] ) ;
}
GET_INSTRUCTION_ARG ( dst , argc ) ;
* dst = Variant ( ) ; // Clear potential previous typed array.
2022-11-27 09:56:53 +02:00
* dst = Array ( array , builtin_type , native_type , * script_type ) ;
2021-03-09 12:32:35 -03:00
ip + = 4 ;
}
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_CONSTRUCT_DICTIONARY ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-13 10:31:14 -03:00
CHECK_SPACE ( 2 + instr_arg_count ) ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
Dictionary dict ;
2020-11-12 10:14:48 -03:00
for ( int i = 0 ; i < argc ; i + + ) {
2020-11-13 10:31:14 -03:00
GET_INSTRUCTION_ARG ( k , i * 2 + 0 ) ;
GET_INSTRUCTION_ARG ( v , i * 2 + 1 ) ;
2020-11-12 10:14:48 -03:00
dict [ * k ] = * v ;
}
2020-11-13 10:31:14 -03:00
GET_INSTRUCTION_ARG ( dst , argc * 2 ) ;
2020-11-12 10:14:48 -03:00
* dst = dict ;
2020-11-13 10:31:14 -03:00
ip + = 2 ;
2020-11-12 10:14:48 -03:00
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CALL_ASYNC )
OPCODE ( OPCODE_CALL_RETURN )
OPCODE ( OPCODE_CALL ) {
2023-01-02 15:29:44 +01:00
bool call_ret = ( _code_ptr [ ip ] ) ! = OPCODE_CALL ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
2023-01-02 15:29:44 +01:00
bool call_async = ( _code_ptr [ ip ] ) = = OPCODE_CALL_ASYNC ;
2020-11-12 10:14:48 -03:00
# endif
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
CHECK_SPACE ( 3 + instr_arg_count ) ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
ip + = instr_arg_count ;
2020-11-12 10:14:48 -03:00
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
2020-11-13 10:31:14 -03:00
int methodname_idx = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( methodname_idx < 0 | | methodname_idx > = _global_names_count ) ;
const StringName * methodname = & _global_names_ptr [ methodname_idx ] ;
GET_INSTRUCTION_ARG ( base , argc ) ;
Variant * * argptrs = instruction_args ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
uint64_t call_time = 0 ;
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
2023-03-05 14:37:11 +02:00
Variant : : Type base_type = base - > get_type ( ) ;
Object * base_obj = base - > get_validated_object ( ) ;
StringName base_class = base_obj ? base_obj - > get_class_name ( ) : StringName ( ) ;
2020-11-12 10:14:48 -03:00
# endif
2023-03-05 14:37:11 +02:00
2020-11-12 10:14:48 -03:00
Callable : : CallError err ;
if ( call_ret ) {
2020-11-13 10:31:14 -03:00
GET_INSTRUCTION_ARG ( ret , argc + 1 ) ;
2022-03-09 14:58:40 +01:00
base - > callp ( * methodname , ( const Variant * * ) argptrs , argc , * ret , err ) ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
2022-12-29 08:57:41 -03:00
if ( ret - > get_type ( ) = = Variant : : NIL ) {
if ( base_type = = Variant : : OBJECT ) {
if ( base_obj ) {
MethodBind * method = ClassDB : : get_method ( base_class , * methodname ) ;
2023-09-04 17:01:33 +02:00
if ( * methodname = = CoreStringName ( free_ ) | | ( method & & ! method - > has_return ( ) ) ) {
2022-12-29 08:57:41 -03:00
err_text = R " (Trying to get a return value of a method that returns " void " ) " ;
OPCODE_BREAK ;
}
}
} else if ( Variant : : has_builtin_method ( base_type , * methodname ) & & ! Variant : : has_builtin_method_return_value ( base_type , * methodname ) ) {
err_text = R " (Trying to get a return value of a method that returns " void " ) " ;
OPCODE_BREAK ;
}
}
2020-11-12 10:14:48 -03:00
if ( ! call_async & & ret - > get_type ( ) = = Variant : : OBJECT ) {
// Check if getting a function state without await.
bool was_freed = false ;
Object * obj = ret - > get_validated_object_with_check ( was_freed ) ;
if ( obj & & obj - > is_class_ptr ( GDScriptFunctionState : : get_class_ptr_static ( ) ) ) {
err_text = R " (Trying to call an async function without " await " .) " ;
OPCODE_BREAK ;
}
}
# endif
} else {
Variant ret ;
2022-03-09 14:58:40 +01:00
base - > callp ( * methodname , ( const Variant * * ) argptrs , argc , ret , err ) ;
2020-11-12 10:14:48 -03:00
}
# ifdef DEBUG_ENABLED
2023-03-05 14:37:11 +02:00
2020-11-12 10:14:48 -03:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
2023-03-05 14:37:11 +02:00
uint64_t t_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
if ( GDScriptLanguage : : get_singleton ( ) - > profile_native_calls & & _profile_count_as_native ( base_obj , * methodname ) ) {
_profile_native_call ( t_taken , * methodname , base_class ) ;
}
function_call_time + = t_taken ;
2020-11-12 10:14:48 -03:00
}
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
String methodstr = * methodname ;
String basestr = _get_var_type ( base ) ;
2021-03-28 11:03:13 -03:00
bool is_callable = false ;
2020-11-12 10:14:48 -03:00
if ( methodstr = = " call " ) {
2021-03-28 11:03:13 -03:00
if ( argc > = 1 & & base - > get_type ( ) ! = Variant : : CALLABLE ) {
2020-11-12 10:14:48 -03:00
methodstr = String ( * argptrs [ 0 ] ) + " (via call) " ;
if ( err . error = = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ) {
err . argument + = 1 ;
}
2021-03-28 11:03:13 -03:00
} else {
methodstr = base - > operator String ( ) + " (Callable) " ;
is_callable = true ;
2020-11-12 10:14:48 -03:00
}
} else if ( methodstr = = " free " ) {
if ( err . error = = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) {
2021-08-26 21:37:17 +02:00
if ( base - > is_ref_counted ( ) ) {
2024-07-12 00:04:59 +02:00
err_text = " Attempted to free a RefCounted object. " ;
2020-11-12 10:14:48 -03:00
OPCODE_BREAK ;
} else if ( base - > get_type ( ) = = Variant : : OBJECT ) {
err_text = " Attempted to free a locked object (calling or emitting). " ;
OPCODE_BREAK ;
}
}
} else if ( methodstr = = " call_recursive " & & basestr = = " TreeItem " ) {
if ( argc > = 1 ) {
methodstr = String ( * argptrs [ 0 ] ) + " (via TreeItem.call_recursive) " ;
if ( err . error = = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ) {
err . argument + = 1 ;
}
}
}
2021-03-28 11:03:13 -03:00
err_text = _get_call_error ( err , " function ' " + methodstr + ( is_callable ? " " : " ' in base ' " + basestr ) + " ' " , ( const Variant * * ) argptrs ) ;
2020-11-12 10:14:48 -03:00
OPCODE_BREAK ;
}
# endif
2020-11-13 10:31:14 -03:00
ip + = 3 ;
2020-11-12 10:14:48 -03:00
}
DISPATCH_OPCODE ;
2020-11-17 10:44:52 -03:00
OPCODE ( OPCODE_CALL_METHOD_BIND )
OPCODE ( OPCODE_CALL_METHOD_BIND_RET ) {
2023-01-02 15:29:44 +01:00
bool call_ret = ( _code_ptr [ ip ] ) = = OPCODE_CALL_METHOD_BIND_RET ;
LOAD_INSTRUCTION_ARGS
2020-11-17 10:44:52 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _methods_count ) ;
MethodBind * method = _methods_ptr [ _code_ptr [ ip + 2 ] ] ;
GET_INSTRUCTION_ARG ( base , argc ) ;
# ifdef DEBUG_ENABLED
bool freed = false ;
Object * base_obj = base - > get_validated_object_with_check ( freed ) ;
if ( freed ) {
2021-10-20 19:09:43 +02:00
err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR ( method ) ;
2020-11-17 10:44:52 -03:00
OPCODE_BREAK ;
} else if ( ! base_obj ) {
2021-10-20 19:09:43 +02:00
err_text = METHOD_CALL_ON_NULL_VALUE_ERROR ( method ) ;
2020-11-17 10:44:52 -03:00
OPCODE_BREAK ;
}
# else
Object * base_obj = base - > operator Object * ( ) ;
# endif
Variant * * argptrs = instruction_args ;
# ifdef DEBUG_ENABLED
uint64_t call_time = 0 ;
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
2020-11-17 10:44:52 -03:00
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
# endif
Callable : : CallError err ;
if ( call_ret ) {
GET_INSTRUCTION_ARG ( ret , argc + 1 ) ;
* ret = method - > call ( base_obj , ( const Variant * * ) argptrs , argc , err ) ;
} else {
method - > call ( base_obj , ( const Variant * * ) argptrs , argc , err ) ;
}
# ifdef DEBUG_ENABLED
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
uint64_t t_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
_profile_native_call ( t_taken , method - > get_name ( ) , method - > get_instance_class ( ) ) ;
function_call_time + = t_taken ;
2020-11-17 10:44:52 -03:00
}
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
String methodstr = method - > get_name ( ) ;
String basestr = _get_var_type ( base ) ;
if ( methodstr = = " call " ) {
if ( argc > = 1 ) {
methodstr = String ( * argptrs [ 0 ] ) + " (via call) " ;
if ( err . error = = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ) {
err . argument + = 1 ;
}
}
} else if ( methodstr = = " free " ) {
if ( err . error = = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) {
2021-08-26 21:37:17 +02:00
if ( base - > is_ref_counted ( ) ) {
2024-07-12 00:04:59 +02:00
err_text = " Attempted to free a RefCounted object. " ;
2020-11-17 10:44:52 -03:00
OPCODE_BREAK ;
} else if ( base - > get_type ( ) = = Variant : : OBJECT ) {
err_text = " Attempted to free a locked object (calling or emitting). " ;
OPCODE_BREAK ;
}
}
}
err_text = _get_call_error ( err , " function ' " + methodstr + " ' in base ' " + basestr + " ' " , ( const Variant * * ) argptrs ) ;
OPCODE_BREAK ;
}
# endif
ip + = 3 ;
}
DISPATCH_OPCODE ;
2021-05-16 11:48:53 -03:00
OPCODE ( OPCODE_CALL_BUILTIN_STATIC ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2021-05-16 11:48:53 -03:00
CHECK_SPACE ( 4 + instr_arg_count ) ;
ip + = instr_arg_count ;
GD_ERR_BREAK ( _code_ptr [ ip + 1 ] < 0 | | _code_ptr [ ip + 1 ] > = Variant : : VARIANT_MAX ) ;
Variant : : Type builtin_type = ( Variant : : Type ) _code_ptr [ ip + 1 ] ;
int methodname_idx = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( methodname_idx < 0 | | methodname_idx > = _global_names_count ) ;
const StringName * methodname = & _global_names_ptr [ methodname_idx ] ;
int argc = _code_ptr [ ip + 3 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GET_INSTRUCTION_ARG ( ret , argc ) ;
const Variant * * argptrs = const_cast < const Variant * * > ( instruction_args ) ;
Callable : : CallError err ;
Variant : : call_static ( builtin_type , * methodname , argptrs , argc , * ret , err ) ;
# ifdef DEBUG_ENABLED
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
err_text = _get_call_error ( err , " static function ' " + methodname - > operator String ( ) + " ' in type ' " + Variant : : get_type_name ( builtin_type ) + " ' " , argptrs ) ;
OPCODE_BREAK ;
}
# endif
ip + = 4 ;
}
DISPATCH_OPCODE ;
2022-04-06 14:14:38 -03:00
OPCODE ( OPCODE_CALL_NATIVE_STATIC ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2022-04-06 14:14:38 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
GD_ERR_BREAK ( _code_ptr [ ip + 1 ] < 0 | | _code_ptr [ ip + 1 ] > = _methods_count ) ;
MethodBind * method = _methods_ptr [ _code_ptr [ ip + 1 ] ] ;
int argc = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GET_INSTRUCTION_ARG ( ret , argc ) ;
const Variant * * argptrs = const_cast < const Variant * * > ( instruction_args ) ;
# ifdef DEBUG_ENABLED
uint64_t call_time = 0 ;
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
2022-04-06 14:14:38 -03:00
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
# endif
Callable : : CallError err ;
* ret = method - > call ( nullptr , argptrs , argc , err ) ;
# ifdef DEBUG_ENABLED
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
uint64_t t_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
_profile_native_call ( t_taken , method - > get_name ( ) , method - > get_instance_class ( ) ) ;
function_call_time + = t_taken ;
2022-04-06 14:14:38 -03:00
}
2023-03-05 14:37:11 +02:00
# endif
2022-04-06 14:14:38 -03:00
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
err_text = _get_call_error ( err , " static function ' " + method - > get_name ( ) . operator String ( ) + " ' in type ' " + method - > get_instance_class ( ) . operator String ( ) + " ' " , argptrs ) ;
OPCODE_BREAK ;
}
ip + = 3 ;
}
DISPATCH_OPCODE ;
2024-04-25 21:05:53 -03:00
OPCODE ( OPCODE_CALL_NATIVE_STATIC_VALIDATED_RETURN ) {
LOAD_INSTRUCTION_ARGS
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _methods_count ) ;
MethodBind * method = _methods_ptr [ _code_ptr [ ip + 2 ] ] ;
Variant * * argptrs = instruction_args ;
# ifdef DEBUG_ENABLED
uint64_t call_time = 0 ;
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
# endif
GET_INSTRUCTION_ARG ( ret , argc ) ;
method - > validated_call ( nullptr , ( const Variant * * ) argptrs , ret ) ;
# ifdef DEBUG_ENABLED
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
uint64_t t_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
_profile_native_call ( t_taken , method - > get_name ( ) , method - > get_instance_class ( ) ) ;
function_call_time + = t_taken ;
}
# endif
ip + = 3 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CALL_NATIVE_STATIC_VALIDATED_NO_RETURN ) {
LOAD_INSTRUCTION_ARGS
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _methods_count ) ;
MethodBind * method = _methods_ptr [ _code_ptr [ ip + 2 ] ] ;
Variant * * argptrs = instruction_args ;
# ifdef DEBUG_ENABLED
uint64_t call_time = 0 ;
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
# endif
GET_INSTRUCTION_ARG ( ret , argc ) ;
VariantInternal : : initialize ( ret , Variant : : NIL ) ;
method - > validated_call ( nullptr , ( const Variant * * ) argptrs , nullptr ) ;
# ifdef DEBUG_ENABLED
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
uint64_t t_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
_profile_native_call ( t_taken , method - > get_name ( ) , method - > get_instance_class ( ) ) ;
function_call_time + = t_taken ;
}
# endif
ip + = 3 ;
}
DISPATCH_OPCODE ;
2023-07-25 12:42:07 -03:00
OPCODE ( OPCODE_CALL_METHOD_BIND_VALIDATED_RETURN ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-17 10:44:52 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _methods_count ) ;
MethodBind * method = _methods_ptr [ _code_ptr [ ip + 2 ] ] ;
GET_INSTRUCTION_ARG ( base , argc ) ;
2023-07-25 12:42:07 -03:00
2020-11-17 10:44:52 -03:00
# ifdef DEBUG_ENABLED
bool freed = false ;
Object * base_obj = base - > get_validated_object_with_check ( freed ) ;
if ( freed ) {
2021-10-20 19:09:43 +02:00
err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR ( method ) ;
2020-11-17 10:44:52 -03:00
OPCODE_BREAK ;
} else if ( ! base_obj ) {
2021-10-20 19:09:43 +02:00
err_text = METHOD_CALL_ON_NULL_VALUE_ERROR ( method ) ;
2020-11-17 10:44:52 -03:00
OPCODE_BREAK ;
}
# else
Object * base_obj = * VariantInternal : : get_object ( base ) ;
# endif
2023-07-25 12:42:07 -03:00
Variant * * argptrs = instruction_args ;
2020-11-17 10:44:52 -03:00
# ifdef DEBUG_ENABLED
uint64_t call_time = 0 ;
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
2020-11-17 10:44:52 -03:00
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
# endif
GET_INSTRUCTION_ARG ( ret , argc + 1 ) ;
2023-07-25 12:42:07 -03:00
method - > validated_call ( base_obj , ( const Variant * * ) argptrs , ret ) ;
2020-11-17 10:44:52 -03:00
# ifdef DEBUG_ENABLED
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
uint64_t t_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
_profile_native_call ( t_taken , method - > get_name ( ) , method - > get_instance_class ( ) ) ;
function_call_time + = t_taken ;
2020-11-17 10:44:52 -03:00
}
# endif
2023-03-05 14:37:11 +02:00
2020-11-17 10:44:52 -03:00
ip + = 3 ;
}
DISPATCH_OPCODE ;
2023-07-25 12:42:07 -03:00
OPCODE ( OPCODE_CALL_METHOD_BIND_VALIDATED_NO_RETURN ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-17 10:44:52 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _methods_count ) ;
MethodBind * method = _methods_ptr [ _code_ptr [ ip + 2 ] ] ;
GET_INSTRUCTION_ARG ( base , argc ) ;
# ifdef DEBUG_ENABLED
bool freed = false ;
Object * base_obj = base - > get_validated_object_with_check ( freed ) ;
if ( freed ) {
2021-10-20 19:09:43 +02:00
err_text = METHOD_CALL_ON_FREED_INSTANCE_ERROR ( method ) ;
2020-11-17 10:44:52 -03:00
OPCODE_BREAK ;
} else if ( ! base_obj ) {
2021-10-20 19:09:43 +02:00
err_text = METHOD_CALL_ON_NULL_VALUE_ERROR ( method ) ;
2020-11-17 10:44:52 -03:00
OPCODE_BREAK ;
}
# else
Object * base_obj = * VariantInternal : : get_object ( base ) ;
# endif
2023-07-25 12:42:07 -03:00
Variant * * argptrs = instruction_args ;
2020-11-17 10:44:52 -03:00
# ifdef DEBUG_ENABLED
uint64_t call_time = 0 ;
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
2020-11-17 10:44:52 -03:00
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
}
# endif
GET_INSTRUCTION_ARG ( ret , argc + 1 ) ;
VariantInternal : : initialize ( ret , Variant : : NIL ) ;
2023-07-25 12:42:07 -03:00
method - > validated_call ( base_obj , ( const Variant * * ) argptrs , nullptr ) ;
2020-11-17 10:44:52 -03:00
# ifdef DEBUG_ENABLED
2023-03-05 14:37:11 +02:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling & & GDScriptLanguage : : get_singleton ( ) - > profile_native_calls ) {
uint64_t t_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
_profile_native_call ( t_taken , method - > get_name ( ) , method - > get_instance_class ( ) ) ;
function_call_time + = t_taken ;
2020-11-17 10:44:52 -03:00
}
# endif
2023-03-05 14:37:11 +02:00
2020-11-17 10:44:52 -03:00
ip + = 3 ;
}
DISPATCH_OPCODE ;
2020-11-18 10:32:28 -03:00
OPCODE ( OPCODE_CALL_BUILTIN_TYPE_VALIDATED ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-18 10:32:28 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GET_INSTRUCTION_ARG ( base , argc ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _builtin_methods_count ) ;
Variant : : ValidatedBuiltInMethod method = _builtin_methods_ptr [ _code_ptr [ ip + 2 ] ] ;
Variant * * argptrs = instruction_args ;
GET_INSTRUCTION_ARG ( ret , argc + 1 ) ;
method ( base , ( const Variant * * ) argptrs , argc , ret ) ;
ip + = 3 ;
}
DISPATCH_OPCODE ;
2020-11-26 11:56:32 -03:00
OPCODE ( OPCODE_CALL_UTILITY ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-13 10:31:14 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( argc < 0 ) ;
2020-11-26 11:56:32 -03:00
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _global_names_count ) ;
StringName function = _global_names_ptr [ _code_ptr [ ip + 2 ] ] ;
2020-11-13 10:31:14 -03:00
Variant * * argptrs = instruction_args ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
GET_INSTRUCTION_ARG ( dst , argc ) ;
2020-11-12 10:14:48 -03:00
Callable : : CallError err ;
2020-11-26 11:56:32 -03:00
Variant : : call_utility_function ( function , dst , ( const Variant * * ) argptrs , argc , err ) ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
2020-11-26 11:56:32 -03:00
String methodstr = function ;
2023-06-30 20:40:02 +03:00
if ( dst - > get_type ( ) = = Variant : : STRING & & ! dst - > operator String ( ) . is_empty ( ) ) {
2020-11-26 11:56:32 -03:00
// Call provided error string.
2023-06-30 20:40:02 +03:00
err_text = vformat ( R " *(Error calling utility function " % s ( ) " : %s)* " , methodstr , * dst ) ;
2020-11-12 10:14:48 -03:00
} else {
2023-06-30 20:40:02 +03:00
err_text = _get_call_error ( err , vformat ( R " *(utility function " % s ( ) " )* " , methodstr ) , ( const Variant * * ) argptrs ) ;
2020-11-26 11:56:32 -03:00
}
OPCODE_BREAK ;
}
# endif
ip + = 3 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CALL_UTILITY_VALIDATED ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-26 11:56:32 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _utilities_count ) ;
Variant : : ValidatedUtilityFunction function = _utilities_ptr [ _code_ptr [ ip + 2 ] ] ;
Variant * * argptrs = instruction_args ;
GET_INSTRUCTION_ARG ( dst , argc ) ;
function ( dst , ( const Variant * * ) argptrs , argc ) ;
ip + = 3 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CALL_GDSCRIPT_UTILITY ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-26 11:56:32 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
ip + = instr_arg_count ;
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
GD_ERR_BREAK ( _code_ptr [ ip + 2 ] < 0 | | _code_ptr [ ip + 2 ] > = _gds_utilities_count ) ;
GDScriptUtilityFunctions : : FunctionPtr function = _gds_utilities_ptr [ _code_ptr [ ip + 2 ] ] ;
Variant * * argptrs = instruction_args ;
GET_INSTRUCTION_ARG ( dst , argc ) ;
Callable : : CallError err ;
function ( dst , ( const Variant * * ) argptrs , argc , err ) ;
# ifdef DEBUG_ENABLED
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
2023-06-30 20:40:02 +03:00
String methodstr = gds_utilities_names [ _code_ptr [ ip + 2 ] ] ;
if ( dst - > get_type ( ) = = Variant : : STRING & & ! dst - > operator String ( ) . is_empty ( ) ) {
2020-11-26 11:56:32 -03:00
// Call provided error string.
2023-06-30 20:40:02 +03:00
err_text = vformat ( R " *(Error calling GDScript utility function " % s ( ) " : %s)* " , methodstr , * dst ) ;
2020-11-26 11:56:32 -03:00
} else {
2023-06-30 20:40:02 +03:00
err_text = _get_call_error ( err , vformat ( R " *(GDScript utility function " % s ( ) " )* " , methodstr ) , ( const Variant * * ) argptrs ) ;
2020-11-12 10:14:48 -03:00
}
OPCODE_BREAK ;
}
# endif
2020-11-13 10:31:14 -03:00
ip + = 3 ;
2020-11-12 10:14:48 -03:00
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CALL_SELF_BASE ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2020-11-13 10:31:14 -03:00
CHECK_SPACE ( 3 + instr_arg_count ) ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
ip + = instr_arg_count ;
2021-06-13 17:40:22 +02:00
int argc = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( argc < 0 ) ;
int self_fun = _code_ptr [ ip + 2 ] ;
2020-11-12 10:14:48 -03:00
# ifdef DEBUG_ENABLED
if ( self_fun < 0 | | self_fun > = _global_names_count ) {
err_text = " compiler bug, function name not found " ;
OPCODE_BREAK ;
}
# endif
const StringName * methodname = & _global_names_ptr [ self_fun ] ;
2020-11-13 10:31:14 -03:00
Variant * * argptrs = instruction_args ;
2020-11-12 10:14:48 -03:00
2020-11-13 10:31:14 -03:00
GET_INSTRUCTION_ARG ( dst , argc ) ;
2020-11-12 10:14:48 -03:00
const GDScript * gds = _script ;
2022-05-13 15:04:37 +02:00
HashMap < StringName , GDScriptFunction * > : : ConstIterator E ;
2020-11-12 10:14:48 -03:00
while ( gds - > base . ptr ( ) ) {
gds = gds - > base . ptr ( ) ;
E = gds - > member_functions . find ( * methodname ) ;
if ( E ) {
break ;
}
}
Callable : : CallError err ;
if ( E ) {
2022-05-13 15:04:37 +02:00
* dst = E - > value - > call ( p_instance , ( const Variant * * ) argptrs , argc , err ) ;
2020-11-12 10:14:48 -03:00
} else if ( gds - > native . ptr ( ) ) {
if ( * methodname ! = GDScriptLanguage : : get_singleton ( ) - > strings . _init ) {
MethodBind * mb = ClassDB : : get_method ( gds - > native - > get_name ( ) , * methodname ) ;
if ( ! mb ) {
err . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
} else {
* dst = mb - > call ( p_instance - > owner , ( const Variant * * ) argptrs , argc , err ) ;
}
} else {
err . error = Callable : : CallError : : CALL_OK ;
}
} else {
if ( * methodname ! = GDScriptLanguage : : get_singleton ( ) - > strings . _init ) {
err . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
} else {
err . error = Callable : : CallError : : CALL_OK ;
}
}
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
String methodstr = * methodname ;
err_text = _get_call_error ( err , " function ' " + methodstr + " ' " , ( const Variant * * ) argptrs ) ;
OPCODE_BREAK ;
}
2020-11-13 10:31:14 -03:00
ip + = 3 ;
2020-11-12 10:14:48 -03:00
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_AWAIT ) {
CHECK_SPACE ( 2 ) ;
2022-09-01 15:44:42 +02:00
// Do the one-shot connect.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( argobj , 0 ) ;
2020-11-12 10:14:48 -03:00
Signal sig ;
bool is_signal = true ;
{
Variant result = * argobj ;
if ( argobj - > get_type ( ) = = Variant : : OBJECT ) {
bool was_freed = false ;
Object * obj = argobj - > get_validated_object_with_check ( was_freed ) ;
if ( was_freed ) {
err_text = " Trying to await on a freed object. " ;
OPCODE_BREAK ;
}
// Is this even possible to be null at this point?
if ( obj ) {
if ( obj - > is_class_ptr ( GDScriptFunctionState : : get_class_ptr_static ( ) ) ) {
2022-05-13 14:03:48 -03:00
result = Signal ( obj , " completed " ) ;
2020-11-12 10:14:48 -03:00
}
}
}
if ( result . get_type ( ) ! = Variant : : SIGNAL ) {
2021-10-14 19:58:10 -03:00
// Not async, return immediately using the target from OPCODE_AWAIT_RESUME.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( target , 2 ) ;
2021-10-14 19:58:10 -03:00
* target = result ;
2020-11-12 10:14:48 -03:00
ip + = 4 ; // Skip OPCODE_AWAIT_RESUME and its data.
is_signal = false ;
} else {
sig = result ;
}
}
if ( is_signal ) {
Ref < GDScriptFunctionState > gdfs = memnew ( GDScriptFunctionState ) ;
gdfs - > function = this ;
gdfs - > state . stack . resize ( alloca_size ) ;
2022-05-13 14:03:48 -03:00
// First 3 stack addresses are special, so we just skip them here.
for ( int i = 3 ; i < _stack_size ; i + + ) {
2020-11-12 10:14:48 -03:00
memnew_placement ( & gdfs - > state . stack . write [ sizeof ( Variant ) * i ] , Variant ( stack [ i ] ) ) ;
}
gdfs - > state . stack_size = _stack_size ;
gdfs - > state . alloca_size = alloca_size ;
gdfs - > state . ip = ip + 2 ;
gdfs - > state . line = line ;
gdfs - > state . script = _script ;
{
2022-09-29 12:53:28 +03:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > mutex ) ;
2020-11-12 10:14:48 -03:00
_script - > pending_func_states . add ( & gdfs - > scripts_list ) ;
if ( p_instance ) {
gdfs - > state . instance = p_instance ;
p_instance - > pending_func_states . add ( & gdfs - > instances_list ) ;
} else {
gdfs - > state . instance = nullptr ;
}
}
# ifdef DEBUG_ENABLED
gdfs - > state . function_name = name ;
2022-12-01 05:20:42 -05:00
gdfs - > state . script_path = _script - > get_script_path ( ) ;
2020-11-12 10:14:48 -03:00
# endif
gdfs - > state . defarg = defarg ;
gdfs - > function = this ;
retvalue = gdfs ;
2022-09-01 15:44:42 +02:00
Error err = sig . connect ( Callable ( gdfs . ptr ( ) , " _signal_callback " ) . bind ( retvalue ) , Object : : CONNECT_ONE_SHOT ) ;
2020-11-12 10:14:48 -03:00
if ( err ! = OK ) {
err_text = " Error connecting to signal: " + sig . get_name ( ) + " during await. " ;
OPCODE_BREAK ;
}
# ifdef DEBUG_ENABLED
exit_ok = true ;
awaited = true ;
# endif
OPCODE_BREAK ;
}
}
DISPATCH_OPCODE ; // Needed for synchronous calls (when result is immediately available).
OPCODE ( OPCODE_AWAIT_RESUME ) {
CHECK_SPACE ( 2 ) ;
# ifdef DEBUG_ENABLED
if ( ! p_state ) {
err_text = ( " Invalid Resume (bug?) " ) ;
OPCODE_BREAK ;
}
# endif
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( result , 0 ) ;
2020-11-12 10:14:48 -03:00
* result = p_state - > result ;
ip + = 2 ;
}
DISPATCH_OPCODE ;
2021-03-28 11:03:13 -03:00
OPCODE ( OPCODE_CREATE_LAMBDA ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2021-03-28 11:03:13 -03:00
CHECK_SPACE ( 2 + instr_arg_count ) ;
ip + = instr_arg_count ;
int captures_count = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( captures_count < 0 ) ;
int lambda_index = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( lambda_index < 0 | | lambda_index > = _lambdas_count ) ;
GDScriptFunction * lambda = _lambdas_ptr [ lambda_index ] ;
Vector < Variant > captures ;
captures . resize ( captures_count ) ;
for ( int i = 0 ; i < captures_count ; i + + ) {
GET_INSTRUCTION_ARG ( arg , i ) ;
captures . write [ i ] = * arg ;
}
GDScriptLambdaCallable * callable = memnew ( GDScriptLambdaCallable ( Ref < GDScript > ( script ) , lambda , captures ) ) ;
GET_INSTRUCTION_ARG ( result , captures_count ) ;
* result = Callable ( callable ) ;
ip + = 3 ;
}
2022-04-20 14:22:22 -03:00
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CREATE_SELF_LAMBDA ) {
2023-01-02 15:29:44 +01:00
LOAD_INSTRUCTION_ARGS
2022-04-20 14:22:22 -03:00
CHECK_SPACE ( 2 + instr_arg_count ) ;
GD_ERR_BREAK ( p_instance = = nullptr ) ;
ip + = instr_arg_count ;
int captures_count = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( captures_count < 0 ) ;
int lambda_index = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( lambda_index < 0 | | lambda_index > = _lambdas_count ) ;
GDScriptFunction * lambda = _lambdas_ptr [ lambda_index ] ;
Vector < Variant > captures ;
captures . resize ( captures_count ) ;
for ( int i = 0 ; i < captures_count ; i + + ) {
GET_INSTRUCTION_ARG ( arg , i ) ;
captures . write [ i ] = * arg ;
}
GDScriptLambdaSelfCallable * callable ;
if ( Object : : cast_to < RefCounted > ( p_instance - > owner ) ) {
callable = memnew ( GDScriptLambdaSelfCallable ( Ref < RefCounted > ( Object : : cast_to < RefCounted > ( p_instance - > owner ) ) , lambda , captures ) ) ;
} else {
callable = memnew ( GDScriptLambdaSelfCallable ( p_instance - > owner , lambda , captures ) ) ;
}
GET_INSTRUCTION_ARG ( result , captures_count ) ;
* result = Callable ( callable ) ;
ip + = 3 ;
}
2021-03-28 11:03:13 -03:00
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_JUMP ) {
CHECK_SPACE ( 2 ) ;
int to = _code_ptr [ ip + 1 ] ;
GD_ERR_BREAK ( to < 0 | | to > _code_size ) ;
ip = to ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_JUMP_IF ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( test , 0 ) ;
2020-11-12 10:14:48 -03:00
bool result = test - > booleanize ( ) ;
if ( result ) {
int to = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( to < 0 | | to > _code_size ) ;
ip = to ;
} else {
ip + = 3 ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_JUMP_IF_NOT ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( test , 0 ) ;
2020-11-12 10:14:48 -03:00
bool result = test - > booleanize ( ) ;
if ( ! result ) {
int to = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( to < 0 | | to > _code_size ) ;
ip = to ;
} else {
ip + = 3 ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_JUMP_TO_DEF_ARGUMENT ) {
CHECK_SPACE ( 2 ) ;
ip = _default_arg_ptr [ defarg ] ;
}
DISPATCH_OPCODE ;
2022-06-27 12:09:51 -03:00
OPCODE ( OPCODE_JUMP_IF_SHARED ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( val , 0 ) ;
2022-06-27 12:09:51 -03:00
if ( val - > is_shared ( ) ) {
int to = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( to < 0 | | to > _code_size ) ;
ip = to ;
} else {
ip + = 3 ;
}
}
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_RETURN ) {
CHECK_SPACE ( 2 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( r , 0 ) ;
2020-11-12 10:14:48 -03:00
retvalue = * r ;
# ifdef DEBUG_ENABLED
exit_ok = true ;
# endif
OPCODE_BREAK ;
}
2021-04-02 10:34:44 -03:00
OPCODE ( OPCODE_RETURN_TYPED_BUILTIN ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( r , 0 ) ;
2021-04-02 10:34:44 -03:00
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
2022-10-05 20:49:35 +02:00
err_text = vformat ( R " (Trying to return value of type " % s " from a function whose return type is " % s " .) " ,
2021-04-02 10:34:44 -03:00
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 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( r , 0 ) ;
2021-04-02 10:34:44 -03:00
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( script_type , 1 ) ;
2021-04-02 10:34:44 -03:00
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
2022-10-05 20:49:35 +02:00
err_text = vformat ( R " (Trying to return value of type " % s " from a function whose return type is " Array [ % s ] " .) " ,
Variant : : get_type_name ( r - > get_type ( ) ) , Variant : : get_type_name ( builtin_type ) ) ;
# endif
2021-04-02 10:34:44 -03:00
OPCODE_BREAK ;
}
2022-11-27 09:56:53 +02:00
Array * array = VariantInternal : : get_array ( r ) ;
2023-04-06 06:12:32 +03:00
if ( array - > get_typed_builtin ( ) ! = ( ( uint32_t ) builtin_type ) | | array - > get_typed_class_name ( ) ! = native_type | | array - > get_typed_script ( ) ! = * script_type ) {
2022-11-27 09:56:53 +02:00
# ifdef DEBUG_ENABLED
err_text = vformat ( R " (Trying to return an array of type " % s " where expected return type is " Array [ % s ] " .) " ,
_get_var_type ( r ) , _get_element_type ( builtin_type , native_type , * script_type ) ) ;
# endif // DEBUG_ENABLED
OPCODE_BREAK ;
}
retvalue = * array ;
# ifdef DEBUG_ENABLED
2021-04-02 10:34:44 -03:00
exit_ok = true ;
# endif // DEBUG_ENABLED
OPCODE_BREAK ;
}
OPCODE ( OPCODE_RETURN_TYPED_NATIVE ) {
CHECK_SPACE ( 3 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( r , 0 ) ;
2021-04-02 10:34:44 -03:00
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( type , 1 ) ;
2021-04-02 10:34:44 -03:00
GDScriptNativeClass * nc = Object : : cast_to < GDScriptNativeClass > ( type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! nc ) ;
if ( r - > get_type ( ) ! = Variant : : OBJECT & & r - > get_type ( ) ! = Variant : : NIL ) {
2022-10-05 20:49:35 +02:00
err_text = vformat ( R " (Trying to return value of type " % s " from a function whose return type is " % s " .) " ,
2021-04-02 10:34:44 -03:00
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
2022-10-05 20:49:35 +02:00
err_text = vformat ( R " (Trying to return value of type " % s " from a function whose return type is " % s " .) " ,
2021-04-02 10:34:44 -03:00
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 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( r , 0 ) ;
2021-04-02 10:34:44 -03:00
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( type , 1 ) ;
2021-04-02 10:34:44 -03:00
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
2022-10-05 20:49:35 +02:00
err_text = vformat ( R " (Trying to return value of type " % s " from a function whose return type is " % s " .) " ,
2023-06-20 12:03:54 +03:00
Variant : : get_type_name ( r - > get_type ( ) ) , GDScript : : debug_get_script_name ( Ref < Script > ( base_type ) ) ) ;
2021-04-02 10:34:44 -03:00
# 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
2022-10-05 20:49:35 +02:00
err_text = vformat ( R " (Trying to return value of type " % s " from a function whose return type is " % s " .) " ,
2023-06-20 12:03:54 +03:00
ret_obj - > get_class_name ( ) , GDScript : : debug_get_script_name ( Ref < GDScript > ( base_type ) ) ) ;
2021-04-02 10:34:44 -03:00
# 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
2022-10-05 20:49:35 +02:00
err_text = vformat ( R " (Trying to return value of type " % s " from a function whose return type is " % s " .) " ,
2023-06-20 12:03:54 +03:00
GDScript : : debug_get_script_name ( ret_obj - > get_script_instance ( ) - > get_script ( ) ) , GDScript : : debug_get_script_name ( Ref < GDScript > ( base_type ) ) ) ;
2021-04-02 10:34:44 -03:00
# endif // DEBUG_ENABLED
OPCODE_BREAK ;
}
}
retvalue = * r ;
# ifdef DEBUG_ENABLED
exit_ok = true ;
# endif // DEBUG_ENABLED
OPCODE_BREAK ;
}
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_ITERATE_BEGIN ) {
2020-11-13 10:31:14 -03:00
CHECK_SPACE ( 8 ) ; // Space for this and a regular iterate.
2020-11-12 10:14:48 -03:00
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-11-12 10:14:48 -03:00
2024-03-18 14:51:46 +03:00
* counter = Variant ( ) ;
2020-11-12 10:14:48 -03:00
bool valid ;
if ( ! container - > iter_init ( * counter , valid ) ) {
# ifdef DEBUG_ENABLED
if ( ! valid ) {
err_text = " Unable to iterate on object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " '. " ;
OPCODE_BREAK ;
}
# endif
2020-11-13 10:31:14 -03:00
int jumpto = _code_ptr [ ip + 4 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-11-12 10:14:48 -03:00
* iterator = container - > iter_get ( * counter , valid ) ;
# ifdef DEBUG_ENABLED
if ( ! valid ) {
err_text = " Unable to obtain iterator object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " '. " ;
OPCODE_BREAK ;
}
# endif
2020-11-13 10:31:14 -03:00
ip + = 5 ; // Skip regular iterate which is always next.
2020-11-12 10:14:48 -03:00
}
}
DISPATCH_OPCODE ;
2020-10-07 09:36:48 -03:00
OPCODE ( OPCODE_ITERATE_BEGIN_INT ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
int64_t size = * VariantInternal : : get_int ( container ) ;
VariantInternal : : initialize ( counter , Variant : : INT ) ;
* VariantInternal : : get_int ( counter ) = 0 ;
if ( size > 0 ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
VariantInternal : : initialize ( iterator , Variant : : INT ) ;
* VariantInternal : : get_int ( iterator ) = 0 ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_FLOAT ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
double size = * VariantInternal : : get_float ( container ) ;
VariantInternal : : initialize ( counter , Variant : : FLOAT ) ;
* VariantInternal : : get_float ( counter ) = 0.0 ;
if ( size > 0 ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
VariantInternal : : initialize ( iterator , Variant : : FLOAT ) ;
* VariantInternal : : get_float ( iterator ) = 0 ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_VECTOR2 ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
Vector2 * bounds = VariantInternal : : get_vector2 ( container ) ;
VariantInternal : : initialize ( counter , Variant : : FLOAT ) ;
* VariantInternal : : get_float ( counter ) = bounds - > x ;
if ( bounds - > x < bounds - > y ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
VariantInternal : : initialize ( iterator , Variant : : FLOAT ) ;
* VariantInternal : : get_float ( iterator ) = bounds - > x ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_VECTOR2I ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
Vector2i * bounds = VariantInternal : : get_vector2i ( container ) ;
VariantInternal : : initialize ( counter , Variant : : FLOAT ) ;
* VariantInternal : : get_int ( counter ) = bounds - > x ;
if ( bounds - > x < bounds - > y ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
VariantInternal : : initialize ( iterator , Variant : : INT ) ;
* VariantInternal : : get_int ( iterator ) = bounds - > x ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_VECTOR3 ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
Vector3 * bounds = VariantInternal : : get_vector3 ( container ) ;
double from = bounds - > x ;
double to = bounds - > y ;
double step = bounds - > z ;
VariantInternal : : initialize ( counter , Variant : : FLOAT ) ;
* VariantInternal : : get_float ( counter ) = from ;
bool do_continue = from = = to ? false : ( from < to ? step > 0 : step < 0 ) ;
if ( do_continue ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
VariantInternal : : initialize ( iterator , Variant : : FLOAT ) ;
* VariantInternal : : get_float ( iterator ) = from ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_VECTOR3I ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
Vector3i * bounds = VariantInternal : : get_vector3i ( container ) ;
int64_t from = bounds - > x ;
int64_t to = bounds - > y ;
int64_t step = bounds - > z ;
VariantInternal : : initialize ( counter , Variant : : INT ) ;
* VariantInternal : : get_int ( counter ) = from ;
bool do_continue = from = = to ? false : ( from < to ? step > 0 : step < 0 ) ;
if ( do_continue ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
VariantInternal : : initialize ( iterator , Variant : : INT ) ;
* VariantInternal : : get_int ( iterator ) = from ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_STRING ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
String * str = VariantInternal : : get_string ( container ) ;
VariantInternal : : initialize ( counter , Variant : : INT ) ;
* VariantInternal : : get_int ( counter ) = 0 ;
2020-12-15 12:04:21 +00:00
if ( ! str - > is_empty ( ) ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
VariantInternal : : initialize ( iterator , Variant : : STRING ) ;
* VariantInternal : : get_string ( iterator ) = str - > substr ( 0 , 1 ) ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_DICTIONARY ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
Dictionary * dict = VariantInternal : : get_dictionary ( container ) ;
const Variant * next = dict - > next ( nullptr ) ;
2020-12-15 12:04:21 +00:00
if ( ! dict - > is_empty ( ) ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-12-21 20:13:05 -08:00
* counter = * next ;
2020-10-07 09:36:48 -03:00
* iterator = * next ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_BEGIN_ARRAY ) {
CHECK_SPACE ( 8 ) ; // Check space for iterate instruction too.
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
Array * array = VariantInternal : : get_array ( container ) ;
VariantInternal : : initialize ( counter , Variant : : INT ) ;
* VariantInternal : : get_int ( counter ) = 0 ;
2020-12-15 12:04:21 +00:00
if ( ! array - > is_empty ( ) ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* iterator = array - > get ( 0 ) ;
// Skip regular iterate.
ip + = 5 ;
} else {
// Jump to end of loop.
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
}
}
DISPATCH_OPCODE ;
# define OPCODE_ITERATE_BEGIN_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_var_ret_type, m_ret_type, m_ret_get_func) \
OPCODE(OPCODE_ITERATE_BEGIN_PACKED_##m_var_type##_ARRAY) { \
CHECK_SPACE(8); \
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR(counter, 0); \
GET_VARIANT_PTR(container, 1); \
2020-10-07 09:36:48 -03:00
Vector<m_elem_type> *array = VariantInternal::m_get_func(container); \
VariantInternal::initialize(counter, Variant::INT); \
*VariantInternal::get_int(counter) = 0; \
2020-12-15 12:04:21 +00:00
if (!array->is_empty()) { \
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR(iterator, 2); \
2020-10-07 09:36:48 -03:00
VariantInternal::initialize(iterator, Variant::m_var_ret_type); \
m_ret_type *it = VariantInternal::m_ret_get_func(iterator); \
*it = array->get(0); \
ip += 5; \
} else { \
int jumpto = _code_ptr[ip + 4]; \
GD_ERR_BREAK(jumpto<0 || jumpto> _code_size); \
ip = jumpto; \
} \
} \
DISPATCH_OPCODE
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( BYTE , uint8_t , get_byte_array , INT , int64_t , get_int ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( INT32 , int32_t , get_int32_array , INT , int64_t , get_int ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( INT64 , int64_t , get_int64_array , INT , int64_t , get_int ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( FLOAT32 , float , get_float32_array , FLOAT , double , get_float ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( FLOAT64 , double , get_float64_array , FLOAT , double , get_float ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( STRING , String , get_string_array , STRING , String , get_string ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( VECTOR2 , Vector2 , get_vector2_array , VECTOR2 , Vector2 , get_vector2 ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( VECTOR3 , Vector3 , get_vector3_array , VECTOR3 , Vector3 , get_vector3 ) ;
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( COLOR , Color , get_color_array , COLOR , Color , get_color ) ;
2024-04-08 07:51:34 -07:00
OPCODE_ITERATE_BEGIN_PACKED_ARRAY ( VECTOR4 , Vector4 , get_vector4_array , VECTOR4 , Vector4 , get_vector4 ) ;
2020-10-07 09:36:48 -03:00
OPCODE ( OPCODE_ITERATE_BEGIN_OBJECT ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
# ifdef DEBUG_ENABLED
bool freed = false ;
Object * obj = container - > get_validated_object_with_check ( freed ) ;
if ( freed ) {
err_text = " Trying to iterate on a previously freed object. " ;
OPCODE_BREAK ;
} else if ( ! obj ) {
err_text = " Trying to iterate on a null value. " ;
OPCODE_BREAK ;
}
# else
Object * obj = * VariantInternal : : get_object ( container ) ;
# endif
2024-03-18 14:51:46 +03:00
* counter = Variant ( ) ;
2020-10-07 09:36:48 -03:00
Array ref ;
ref . push_back ( * counter ) ;
Variant vref ;
VariantInternal : : initialize ( & vref , Variant : : ARRAY ) ;
* VariantInternal : : get_array ( & vref ) = ref ;
2024-03-18 14:51:46 +03:00
const Variant * args [ ] = { & vref } ;
2020-10-07 09:36:48 -03:00
Callable : : CallError ce ;
2023-09-04 17:01:33 +02:00
Variant has_next = obj - > callp ( CoreStringName ( _iter_init ) , args , 1 , ce ) ;
2020-10-07 09:36:48 -03:00
# ifdef DEBUG_ENABLED
2024-03-18 14:51:46 +03:00
if ( ref . size ( ) ! = 1 | | ce . error ! = Callable : : CallError : : CALL_OK ) {
2020-10-07 09:36:48 -03:00
err_text = vformat ( R " (There was an error calling " _iter_next " on iterator object of type %s.) " , * container ) ;
OPCODE_BREAK ;
}
# endif
if ( ! has_next . booleanize ( ) ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2024-03-18 14:51:46 +03:00
* counter = ref [ 0 ] ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2023-09-04 17:01:33 +02:00
* iterator = obj - > callp ( CoreStringName ( _iter_get ) , ( const Variant * * ) & counter , 1 , ce ) ;
2020-10-07 09:36:48 -03:00
# ifdef DEBUG_ENABLED
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
err_text = vformat ( R " (There was an error calling " _iter_get " on iterator object of type %s.) " , * container ) ;
OPCODE_BREAK ;
}
# endif
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_ITERATE ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-11-12 10:14:48 -03:00
bool valid ;
if ( ! container - > iter_next ( * counter , valid ) ) {
# ifdef DEBUG_ENABLED
if ( ! valid ) {
err_text = " Unable to iterate on object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " ' (type changed since first iteration?). " ;
OPCODE_BREAK ;
}
# endif
2020-11-13 10:31:14 -03:00
int jumpto = _code_ptr [ ip + 4 ] ;
2020-11-12 10:14:48 -03:00
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-11-12 10:14:48 -03:00
* iterator = container - > iter_get ( * counter , valid ) ;
# ifdef DEBUG_ENABLED
if ( ! valid ) {
err_text = " Unable to obtain iterator object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " ' (but was obtained on first iteration?). " ;
OPCODE_BREAK ;
}
# endif
ip + = 5 ; //loop again
}
}
DISPATCH_OPCODE ;
2020-10-07 09:36:48 -03:00
OPCODE ( OPCODE_ITERATE_INT ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
int64_t size = * VariantInternal : : get_int ( container ) ;
int64_t * count = VariantInternal : : get_int ( counter ) ;
( * count ) + + ;
if ( * count > = size ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* VariantInternal : : get_int ( iterator ) = * count ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_FLOAT ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
double size = * VariantInternal : : get_float ( container ) ;
double * count = VariantInternal : : get_float ( counter ) ;
( * count ) + + ;
if ( * count > = size ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* VariantInternal : : get_float ( iterator ) = * count ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_VECTOR2 ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
const Vector2 * bounds = VariantInternal : : get_vector2 ( ( const Variant * ) container ) ;
double * count = VariantInternal : : get_float ( counter ) ;
( * count ) + + ;
if ( * count > = bounds - > y ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* VariantInternal : : get_float ( iterator ) = * count ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_VECTOR2I ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
const Vector2i * bounds = VariantInternal : : get_vector2i ( ( const Variant * ) container ) ;
int64_t * count = VariantInternal : : get_int ( counter ) ;
( * count ) + + ;
if ( * count > = bounds - > y ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* VariantInternal : : get_int ( iterator ) = * count ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_VECTOR3 ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
const Vector3 * bounds = VariantInternal : : get_vector3 ( ( const Variant * ) container ) ;
double * count = VariantInternal : : get_float ( counter ) ;
* count + = bounds - > z ;
if ( ( bounds - > z < 0 & & * count < = bounds - > y ) | | ( bounds - > z > 0 & & * count > = bounds - > y ) ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* VariantInternal : : get_float ( iterator ) = * count ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_VECTOR3I ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
const Vector3i * bounds = VariantInternal : : get_vector3i ( ( const Variant * ) container ) ;
int64_t * count = VariantInternal : : get_int ( counter ) ;
* count + = bounds - > z ;
if ( ( bounds - > z < 0 & & * count < = bounds - > y ) | | ( bounds - > z > 0 & & * count > = bounds - > y ) ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* VariantInternal : : get_int ( iterator ) = * count ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_STRING ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
const String * str = VariantInternal : : get_string ( ( const Variant * ) container ) ;
int64_t * idx = VariantInternal : : get_int ( counter ) ;
( * idx ) + + ;
if ( * idx > = str - > length ( ) ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* VariantInternal : : get_string ( iterator ) = str - > substr ( * idx , 1 ) ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_DICTIONARY ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
const Dictionary * dict = VariantInternal : : get_dictionary ( ( const Variant * ) container ) ;
const Variant * next = dict - > next ( counter ) ;
if ( ! next ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* counter = * next ;
* iterator = * next ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ITERATE_ARRAY ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
const Array * array = VariantInternal : : get_array ( ( const Variant * ) container ) ;
int64_t * idx = VariantInternal : : get_int ( counter ) ;
( * idx ) + + ;
if ( * idx > = array - > size ( ) ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2020-10-07 09:36:48 -03:00
* iterator = array - > get ( * idx ) ;
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
# define OPCODE_ITERATE_PACKED_ARRAY(m_var_type, m_elem_type, m_get_func, m_ret_get_func) \
OPCODE(OPCODE_ITERATE_PACKED_##m_var_type##_ARRAY) { \
CHECK_SPACE(4); \
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR(counter, 0); \
GET_VARIANT_PTR(container, 1); \
2020-10-07 09:36:48 -03:00
const Vector<m_elem_type> *array = VariantInternal::m_get_func((const Variant *)container); \
int64_t *idx = VariantInternal::get_int(counter); \
(*idx)++; \
if (*idx >= array->size()) { \
int jumpto = _code_ptr[ip + 4]; \
GD_ERR_BREAK(jumpto<0 || jumpto> _code_size); \
ip = jumpto; \
} else { \
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR(iterator, 2); \
2020-10-07 09:36:48 -03:00
*VariantInternal::m_ret_get_func(iterator) = array->get(*idx); \
ip += 5; \
} \
} \
DISPATCH_OPCODE
OPCODE_ITERATE_PACKED_ARRAY ( BYTE , uint8_t , get_byte_array , get_int ) ;
OPCODE_ITERATE_PACKED_ARRAY ( INT32 , int32_t , get_int32_array , get_int ) ;
OPCODE_ITERATE_PACKED_ARRAY ( INT64 , int64_t , get_int64_array , get_int ) ;
OPCODE_ITERATE_PACKED_ARRAY ( FLOAT32 , float , get_float32_array , get_float ) ;
OPCODE_ITERATE_PACKED_ARRAY ( FLOAT64 , double , get_float64_array , get_float ) ;
OPCODE_ITERATE_PACKED_ARRAY ( STRING , String , get_string_array , get_string ) ;
OPCODE_ITERATE_PACKED_ARRAY ( VECTOR2 , Vector2 , get_vector2_array , get_vector2 ) ;
OPCODE_ITERATE_PACKED_ARRAY ( VECTOR3 , Vector3 , get_vector3_array , get_vector3 ) ;
OPCODE_ITERATE_PACKED_ARRAY ( COLOR , Color , get_color_array , get_color ) ;
2024-04-08 07:51:34 -07:00
OPCODE_ITERATE_PACKED_ARRAY ( VECTOR4 , Vector4 , get_vector4_array , get_vector4 ) ;
2020-10-07 09:36:48 -03:00
OPCODE ( OPCODE_ITERATE_OBJECT ) {
CHECK_SPACE ( 4 ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( counter , 0 ) ;
GET_VARIANT_PTR ( container , 1 ) ;
2020-10-07 09:36:48 -03:00
# ifdef DEBUG_ENABLED
bool freed = false ;
Object * obj = container - > get_validated_object_with_check ( freed ) ;
if ( freed ) {
err_text = " Trying to iterate on a previously freed object. " ;
OPCODE_BREAK ;
} else if ( ! obj ) {
err_text = " Trying to iterate on a null value. " ;
OPCODE_BREAK ;
}
# else
Object * obj = * VariantInternal : : get_object ( container ) ;
# endif
2024-03-18 14:51:46 +03:00
2020-10-07 09:36:48 -03:00
Array ref ;
ref . push_back ( * counter ) ;
Variant vref ;
VariantInternal : : initialize ( & vref , Variant : : ARRAY ) ;
* VariantInternal : : get_array ( & vref ) = ref ;
2024-03-18 14:51:46 +03:00
const Variant * args [ ] = { & vref } ;
2020-10-07 09:36:48 -03:00
Callable : : CallError ce ;
2023-09-04 17:01:33 +02:00
Variant has_next = obj - > callp ( CoreStringName ( _iter_next ) , args , 1 , ce ) ;
2020-10-07 09:36:48 -03:00
# ifdef DEBUG_ENABLED
2024-03-18 14:51:46 +03:00
if ( ref . size ( ) ! = 1 | | ce . error ! = Callable : : CallError : : CALL_OK ) {
2020-10-07 09:36:48 -03:00
err_text = vformat ( R " (There was an error calling " _iter_next " on iterator object of type %s.) " , * container ) ;
OPCODE_BREAK ;
}
# endif
if ( ! has_next . booleanize ( ) ) {
int jumpto = _code_ptr [ ip + 4 ] ;
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
ip = jumpto ;
} else {
2024-03-18 14:51:46 +03:00
* counter = ref [ 0 ] ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( iterator , 2 ) ;
2023-09-04 17:01:33 +02:00
* iterator = obj - > callp ( CoreStringName ( _iter_get ) , ( const Variant * * ) & counter , 1 , ce ) ;
2020-10-07 09:36:48 -03:00
# ifdef DEBUG_ENABLED
if ( ce . error ! = Callable : : CallError : : CALL_OK ) {
err_text = vformat ( R " (There was an error calling " _iter_get " on iterator object of type %s.) " , * container ) ;
OPCODE_BREAK ;
}
# endif
ip + = 5 ; // Loop again.
}
}
DISPATCH_OPCODE ;
2021-09-01 16:01:39 -03:00
OPCODE ( OPCODE_STORE_GLOBAL ) {
CHECK_SPACE ( 3 ) ;
int global_idx = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( global_idx < 0 | | global_idx > = GDScriptLanguage : : get_singleton ( ) - > get_global_array_size ( ) ) ;
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
2021-09-01 16:01:39 -03:00
* dst = GDScriptLanguage : : get_singleton ( ) - > get_global_array ( ) [ global_idx ] ;
ip + = 3 ;
}
DISPATCH_OPCODE ;
2021-04-08 11:55:24 -03:00
OPCODE ( OPCODE_STORE_NAMED_GLOBAL ) {
CHECK_SPACE ( 3 ) ;
int globalname_idx = _code_ptr [ ip + 2 ] ;
GD_ERR_BREAK ( globalname_idx < 0 | | globalname_idx > = _global_names_count ) ;
const StringName * globalname = & _global_names_ptr [ globalname_idx ] ;
2022-07-27 23:37:42 +01:00
GD_ERR_BREAK ( ! GDScriptLanguage : : get_singleton ( ) - > get_named_globals_map ( ) . has ( * globalname ) ) ;
2021-04-08 11:55:24 -03:00
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( dst , 0 ) ;
2021-04-08 11:55:24 -03:00
* dst = GDScriptLanguage : : get_singleton ( ) - > get_named_globals_map ( ) [ * globalname ] ;
ip + = 3 ;
}
DISPATCH_OPCODE ;
2021-04-16 12:04:08 -03:00
# define OPCODE_TYPE_ADJUST(m_v_type, m_c_type) \
OPCODE(OPCODE_TYPE_ADJUST_##m_v_type) { \
CHECK_SPACE(2); \
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR(arg, 0); \
2021-04-16 12:04:08 -03:00
VariantTypeAdjust<m_c_type>::adjust(arg); \
ip += 2; \
} \
DISPATCH_OPCODE
OPCODE_TYPE_ADJUST ( BOOL , bool ) ;
OPCODE_TYPE_ADJUST ( INT , int64_t ) ;
OPCODE_TYPE_ADJUST ( FLOAT , double ) ;
OPCODE_TYPE_ADJUST ( STRING , String ) ;
OPCODE_TYPE_ADJUST ( VECTOR2 , Vector2 ) ;
OPCODE_TYPE_ADJUST ( VECTOR2I , Vector2i ) ;
OPCODE_TYPE_ADJUST ( RECT2 , Rect2 ) ;
OPCODE_TYPE_ADJUST ( RECT2I , Rect2i ) ;
OPCODE_TYPE_ADJUST ( VECTOR3 , Vector3 ) ;
OPCODE_TYPE_ADJUST ( VECTOR3I , Vector3i ) ;
OPCODE_TYPE_ADJUST ( TRANSFORM2D , Transform2D ) ;
2022-07-20 01:11:13 +02:00
OPCODE_TYPE_ADJUST ( VECTOR4 , Vector4 ) ;
OPCODE_TYPE_ADJUST ( VECTOR4I , Vector4i ) ;
2021-04-16 12:04:08 -03:00
OPCODE_TYPE_ADJUST ( PLANE , Plane ) ;
2021-01-20 07:02:02 +00:00
OPCODE_TYPE_ADJUST ( QUATERNION , Quaternion ) ;
2021-04-16 12:04:08 -03:00
OPCODE_TYPE_ADJUST ( AABB , AABB ) ;
OPCODE_TYPE_ADJUST ( BASIS , Basis ) ;
2022-04-07 19:47:11 -05:00
OPCODE_TYPE_ADJUST ( TRANSFORM3D , Transform3D ) ;
2022-07-20 01:11:13 +02:00
OPCODE_TYPE_ADJUST ( PROJECTION , Projection ) ;
2021-04-16 12:04:08 -03:00
OPCODE_TYPE_ADJUST ( COLOR , Color ) ;
OPCODE_TYPE_ADJUST ( STRING_NAME , StringName ) ;
OPCODE_TYPE_ADJUST ( NODE_PATH , NodePath ) ;
OPCODE_TYPE_ADJUST ( RID , RID ) ;
OPCODE_TYPE_ADJUST ( OBJECT , Object * ) ;
OPCODE_TYPE_ADJUST ( CALLABLE , Callable ) ;
OPCODE_TYPE_ADJUST ( SIGNAL , Signal ) ;
OPCODE_TYPE_ADJUST ( DICTIONARY , Dictionary ) ;
OPCODE_TYPE_ADJUST ( ARRAY , Array ) ;
OPCODE_TYPE_ADJUST ( PACKED_BYTE_ARRAY , PackedByteArray ) ;
OPCODE_TYPE_ADJUST ( PACKED_INT32_ARRAY , PackedInt32Array ) ;
OPCODE_TYPE_ADJUST ( PACKED_INT64_ARRAY , PackedInt64Array ) ;
OPCODE_TYPE_ADJUST ( PACKED_FLOAT32_ARRAY , PackedFloat32Array ) ;
OPCODE_TYPE_ADJUST ( PACKED_FLOAT64_ARRAY , PackedFloat64Array ) ;
OPCODE_TYPE_ADJUST ( PACKED_STRING_ARRAY , PackedStringArray ) ;
OPCODE_TYPE_ADJUST ( PACKED_VECTOR2_ARRAY , PackedVector2Array ) ;
OPCODE_TYPE_ADJUST ( PACKED_VECTOR3_ARRAY , PackedVector3Array ) ;
OPCODE_TYPE_ADJUST ( PACKED_COLOR_ARRAY , PackedColorArray ) ;
2024-04-08 07:51:34 -07:00
OPCODE_TYPE_ADJUST ( PACKED_VECTOR4_ARRAY , PackedVector4Array ) ;
2021-04-16 12:04:08 -03:00
2020-11-12 10:14:48 -03:00
OPCODE ( OPCODE_ASSERT ) {
CHECK_SPACE ( 3 ) ;
# ifdef DEBUG_ENABLED
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( test , 0 ) ;
2020-11-12 10:14:48 -03:00
bool result = test - > booleanize ( ) ;
if ( ! result ) {
String message_str ;
if ( _code_ptr [ ip + 2 ] ! = 0 ) {
2023-01-02 15:29:44 +01:00
GET_VARIANT_PTR ( message , 1 ) ;
2023-02-08 20:19:24 +01:00
Variant message_var = * message ;
if ( message - > get_type ( ) ! = Variant : : NIL ) {
message_str = message_var ;
}
2020-11-12 10:14:48 -03:00
}
2020-12-15 12:04:21 +00:00
if ( message_str . is_empty ( ) ) {
2020-11-12 10:14:48 -03:00
err_text = " Assertion failed. " ;
} else {
err_text = " Assertion failed: " + message_str ;
}
OPCODE_BREAK ;
}
# endif
ip + = 3 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_BREAKPOINT ) {
# ifdef DEBUG_ENABLED
if ( EngineDebugger : : is_active ( ) ) {
GDScriptLanguage : : get_singleton ( ) - > debug_break ( " Breakpoint Statement " , true ) ;
}
# endif
ip + = 1 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_LINE ) {
CHECK_SPACE ( 2 ) ;
line = _code_ptr [ ip + 1 ] ;
ip + = 2 ;
if ( EngineDebugger : : is_active ( ) ) {
// line
bool do_break = false ;
2023-04-29 17:20:38 +02:00
if ( unlikely ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) > 0 ) ) {
2020-11-12 10:14:48 -03:00
if ( EngineDebugger : : get_script_debugger ( ) - > get_depth ( ) < = 0 ) {
EngineDebugger : : get_script_debugger ( ) - > set_lines_left ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) - 1 ) ;
}
if ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) < = 0 ) {
do_break = true ;
}
}
if ( EngineDebugger : : get_script_debugger ( ) - > is_breakpoint ( line , source ) ) {
do_break = true ;
}
2023-04-29 17:20:38 +02:00
if ( unlikely ( do_break ) ) {
2020-11-12 10:14:48 -03:00
GDScriptLanguage : : get_singleton ( ) - > debug_break ( " Breakpoint " , true ) ;
}
EngineDebugger : : get_singleton ( ) - > line_poll ( ) ;
}
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_END ) {
# ifdef DEBUG_ENABLED
exit_ok = true ;
# endif
OPCODE_BREAK ;
}
#if 0 // Enable for debugging.
default: {
err_text = "Illegal opcode " + itos(_code_ptr[ip]) + " at address " + itos(ip);
OPCODE_BREAK;
}
#endif
}
OPCODES_END
# ifdef DEBUG_ENABLED
if ( exit_ok ) {
OPCODE_OUT ;
}
//error
// function, file, line, error, explanation
String err_file ;
2023-04-24 15:30:51 +02:00
bool instance_valid_with_script = p_instance & & ObjectDB : : get_instance ( p_instance - > owner_id ) ! = nullptr & & p_instance - > script - > is_valid ( ) ;
if ( instance_valid_with_script & & ! get_script ( ) - > path . is_empty ( ) ) {
err_file = get_script ( ) - > path ;
2020-11-12 10:14:48 -03:00
} else if ( script ) {
err_file = script - > path ;
}
2021-12-09 03:42:46 -06:00
if ( err_file . is_empty ( ) ) {
2020-11-12 10:14:48 -03:00
err_file = " <built-in> " ;
}
String err_func = name ;
2023-08-28 19:20:10 +03:00
if ( instance_valid_with_script & & p_instance - > script - > local_name ! = StringName ( ) ) {
err_func = p_instance - > script - > local_name . operator String ( ) + " . " + err_func ;
2020-11-12 10:14:48 -03:00
}
int err_line = line ;
2021-12-09 03:42:46 -06:00
if ( err_text . is_empty ( ) ) {
2021-11-09 12:10:09 +01:00
err_text = " Internal script error! Opcode: " + itos ( last_opcode ) + " (please report). " ;
2020-11-12 10:14:48 -03:00
}
if ( ! GDScriptLanguage : : get_singleton ( ) - > debug_break ( err_text , false ) ) {
// debugger break did not happen
2021-09-22 17:36:40 +02:00
_err_print_error ( err_func . utf8 ( ) . get_data ( ) , err_file . utf8 ( ) . get_data ( ) , err_line , err_text . utf8 ( ) . get_data ( ) , false , ERR_HANDLER_SCRIPT ) ;
2020-11-12 10:14:48 -03:00
}
2022-02-17 15:18:43 +00:00
// Get a default return type in case of failure
retvalue = _get_default_variant_for_data_type ( return_type ) ;
2022-06-22 20:54:01 +04:00
# endif
2022-02-17 15:18:43 +00:00
2020-11-12 10:14:48 -03:00
OPCODE_OUT ;
}
OPCODES_OUT
# ifdef DEBUG_ENABLED
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
uint64_t time_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - function_start_time ;
2023-04-29 17:20:38 +02:00
profile . total_time . add ( time_taken ) ;
profile . self_time . add ( time_taken - function_call_time ) ;
profile . frame_total_time . add ( time_taken ) ;
profile . frame_self_time . add ( time_taken - function_call_time ) ;
if ( Thread : : get_caller_id ( ) = = Thread : : get_main_id ( ) ) {
GDScriptLanguage : : get_singleton ( ) - > script_frame_time + = time_taken - function_call_time ;
}
2020-11-12 10:14:48 -03:00
}
2022-05-27 09:13:25 -03:00
// Check if this is not the last time it was interrupted by `await` or if it's the first time executing.
// If that is the case then we exit the function as normal. Otherwise we postpone it until the last `await` is completed.
2022-05-13 14:03:48 -03:00
// This ensures the call stack can be properly shown when using `await`, showing what resumed the function.
2022-05-27 09:13:25 -03:00
if ( ! p_state | | awaited ) {
2020-11-12 10:14:48 -03:00
if ( EngineDebugger : : is_active ( ) ) {
GDScriptLanguage : : get_singleton ( ) - > exit_function ( ) ;
}
2022-05-27 09:13:25 -03:00
# endif
// Free stack, except reserved addresses.
2023-05-16 13:03:53 +03:00
for ( int i = FIXED_ADDRESSES_MAX ; i < _stack_size ; i + + ) {
2022-05-27 09:13:25 -03:00
stack [ i ] . ~ Variant ( ) ;
}
# ifdef DEBUG_ENABLED
2020-11-12 10:14:48 -03:00
}
# endif
2022-05-27 09:13:25 -03:00
// Always free reserved addresses, since they are never copied.
2023-05-16 13:03:53 +03:00
for ( int i = 0 ; i < FIXED_ADDRESSES_MAX ; i + + ) {
2022-05-27 09:13:25 -03:00
stack [ i ] . ~ Variant ( ) ;
2022-05-13 14:03:48 -03:00
}
2023-02-07 17:09:40 -03:00
call_depth - - ;
2020-11-12 10:14:48 -03:00
return retvalue ;
}