2017-03-05 22:47:28 +08:00
/*************************************************************************/
2017-11-17 01:38:18 +08:00
/* gdscript_function.cpp */
2017-03-05 22:47:28 +08:00
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 20:16:55 +08:00
/* https://godotengine.org */
2017-03-05 22:47:28 +08:00
/*************************************************************************/
2020-01-01 18:16:22 +08:00
/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
2017-03-05 22:47:28 +08:00
/* */
/* 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. */
/*************************************************************************/
2018-01-05 07:50:27 +08:00
2017-11-17 01:38:18 +08:00
# include "gdscript_function.h"
2017-03-05 22:47:28 +08:00
2018-09-12 00:13:45 +08:00
# include "core/os/os.h"
2017-11-17 01:38:18 +08:00
# include "gdscript.h"
# include "gdscript_functions.h"
2016-06-01 09:28:27 +08:00
2020-02-19 20:15:16 +08:00
Variant * GDScriptFunction : : _get_variant ( int p_address , GDScriptInstance * p_instance , GDScript * p_script , Variant & self , Variant & static_ref , Variant * p_stack , String & r_error ) const {
2017-03-05 23:44:50 +08:00
int address = p_address & ADDR_MASK ;
2016-06-01 09:28:27 +08:00
//sequential table (jump table generated by compiler)
2017-03-05 23:44:50 +08:00
switch ( ( p_address & ADDR_TYPE_MASK ) > > ADDR_BITS ) {
2016-06-01 09:28:27 +08:00
case ADDR_TYPE_SELF : {
2017-09-24 02:58:57 +08:00
# ifdef DEBUG_ENABLED
2017-09-20 17:04:50 +08:00
if ( unlikely ( ! p_instance ) ) {
2017-03-05 23:44:50 +08:00
r_error = " Cannot access self without instance. " ;
2020-04-02 07:20:12 +08:00
return nullptr ;
2016-06-01 09:28:27 +08:00
}
2017-09-24 02:58:57 +08:00
# endif
2016-06-01 09:28:27 +08:00
return & self ;
} break ;
case ADDR_TYPE_CLASS : {
2020-02-19 20:15:16 +08:00
return & static_ref ;
2016-06-01 09:28:27 +08:00
} break ;
case ADDR_TYPE_MEMBER : {
2017-09-24 02:58:57 +08:00
# ifdef DEBUG_ENABLED
2017-09-20 17:04:50 +08:00
if ( unlikely ( ! p_instance ) ) {
2017-03-05 23:44:50 +08:00
r_error = " Cannot access member without instance. " ;
2020-04-02 07:20:12 +08:00
return nullptr ;
2016-06-01 09:28:27 +08:00
}
2017-09-24 02:58:57 +08:00
# endif
//member indexing is O(1)
2018-07-25 09:11:03 +08:00
return & p_instance - > members . write [ address ] ;
2016-06-01 09:28:27 +08:00
} break ;
case ADDR_TYPE_CLASS_CONSTANT : {
//todo change to index!
2020-01-17 06:12:45 +08:00
GDScript * s = p_script ;
2017-09-24 02:58:57 +08:00
# ifdef DEBUG_ENABLED
2020-04-02 07:20:12 +08:00
ERR_FAIL_INDEX_V ( address , _global_names_count , nullptr ) ;
2017-09-24 02:58:57 +08:00
# endif
2016-06-01 09:28:27 +08:00
const StringName * sn = & _global_names_ptr [ address ] ;
2020-01-17 06:12:45 +08:00
while ( s ) {
GDScript * o = s ;
while ( o ) {
Map < StringName , Variant > : : Element * E = o - > constants . find ( * sn ) ;
2016-06-01 09:28:27 +08:00
if ( E ) {
return & E - > get ( ) ;
}
2020-01-17 06:12:45 +08:00
o = o - > _owner ;
2016-06-01 09:28:27 +08:00
}
2020-01-17 06:12:45 +08:00
s = s - > _base ;
2016-06-01 09:28:27 +08:00
}
2020-04-02 07:20:12 +08:00
ERR_FAIL_V_MSG ( nullptr , " GDScriptCompiler bug. " ) ;
2016-06-01 09:28:27 +08:00
} break ;
case ADDR_TYPE_LOCAL_CONSTANT : {
2017-09-24 02:58:57 +08:00
# ifdef DEBUG_ENABLED
2020-04-02 07:20:12 +08:00
ERR_FAIL_INDEX_V ( address , _constant_count , nullptr ) ;
2017-09-24 02:58:57 +08:00
# endif
2016-06-01 09:28:27 +08:00
return & _constants_ptr [ address ] ;
} break ;
case ADDR_TYPE_STACK :
case ADDR_TYPE_STACK_VARIABLE : {
2017-09-24 02:58:57 +08:00
# ifdef DEBUG_ENABLED
2020-04-02 07:20:12 +08:00
ERR_FAIL_INDEX_V ( address , _stack_size , nullptr ) ;
2017-09-24 02:58:57 +08:00
# endif
2016-06-01 09:28:27 +08:00
return & p_stack [ address ] ;
} break ;
case ADDR_TYPE_GLOBAL : {
2017-09-24 02:58:57 +08:00
# ifdef DEBUG_ENABLED
2020-04-02 07:20:12 +08:00
ERR_FAIL_INDEX_V ( address , GDScriptLanguage : : get_singleton ( ) - > get_global_array_size ( ) , nullptr ) ;
2017-09-24 02:58:57 +08:00
# endif
2016-06-01 09:28:27 +08:00
return & GDScriptLanguage : : get_singleton ( ) - > get_global_array ( ) [ address ] ;
} break ;
2018-05-01 22:06:23 +08:00
# ifdef TOOLS_ENABLED
case ADDR_TYPE_NAMED_GLOBAL : {
# ifdef DEBUG_ENABLED
2020-04-02 07:20:12 +08:00
ERR_FAIL_INDEX_V ( address , _named_globals_count , nullptr ) ;
2018-05-01 22:06:23 +08:00
# endif
StringName id = _named_globals_ptr [ address ] ;
if ( GDScriptLanguage : : get_singleton ( ) - > get_named_globals_map ( ) . has ( id ) ) {
return ( Variant * ) & GDScriptLanguage : : get_singleton ( ) - > get_named_globals_map ( ) [ id ] ;
} else {
r_error = " Autoload singleton ' " + String ( id ) + " ' has been removed. " ;
2020-04-02 07:20:12 +08:00
return nullptr ;
2018-05-01 22:06:23 +08:00
}
} break ;
# endif
2016-06-01 09:28:27 +08:00
case ADDR_TYPE_NIL : {
return & nil ;
} break ;
}
2020-04-02 07:20:12 +08:00
ERR_FAIL_V_MSG ( nullptr , " Bad code! (unknown addressing mode). " ) ;
return nullptr ;
2016-06-01 09:28:27 +08:00
}
2018-10-03 22:13:34 +08:00
# ifdef DEBUG_ENABLED
2019-06-18 17:27:43 +08:00
static String _get_var_type ( const Variant * p_var ) {
2016-06-01 09:28:27 +08:00
String basestr ;
2019-06-18 17:27:43 +08:00
if ( p_var - > get_type ( ) = = Variant : : OBJECT ) {
2020-02-14 03:03:10 +08:00
bool was_freed ;
Object * bobj = p_var - > get_validated_object_with_check ( was_freed ) ;
2016-06-01 09:28:27 +08:00
if ( ! bobj ) {
2020-02-14 03:03:10 +08:00
if ( was_freed ) {
basestr = " null instance " ;
2016-06-01 09:28:27 +08:00
} else {
2020-02-14 03:03:10 +08:00
basestr = " previously freed " ;
2016-06-01 09:28:27 +08:00
}
2020-02-14 03:03:10 +08:00
} else {
2020-05-14 22:41:43 +08:00
if ( bobj - > get_script_instance ( ) ) {
2020-02-14 03:03:10 +08:00
basestr = bobj - > get_class ( ) + " ( " + bobj - > get_script_instance ( ) - > get_script ( ) - > get_path ( ) . get_file ( ) + " ) " ;
2020-05-14 22:41:43 +08:00
} else {
2020-02-14 03:03:10 +08:00
basestr = bobj - > get_class ( ) ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
}
} else {
2019-06-18 17:27:43 +08:00
basestr = Variant : : get_type_name ( p_var - > get_type ( ) ) ;
2016-06-01 09:28:27 +08:00
}
return basestr ;
}
2019-06-18 17:27:43 +08:00
# endif // DEBUG_ENABLED
2020-02-20 03:27:19 +08:00
String GDScriptFunction : : _get_call_error ( const Callable : : CallError & p_err , const String & p_where , const Variant * * argptrs ) const {
2019-06-18 17:27:43 +08:00
String err_text ;
2020-02-20 03:27:19 +08:00
if ( p_err . error = = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ) {
2019-06-18 17:27:43 +08:00
int errorarg = p_err . argument ;
// 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. " ;
} else
# endif // DEBUG_ENABLED
{
2020-02-20 03:27:19 +08:00
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 ) ) + " . " ;
2019-06-18 17:27:43 +08:00
}
2020-02-20 03:27:19 +08:00
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ) {
2019-06-18 17:27:43 +08:00
err_text = " Invalid call to " + p_where + " . Expected " + itos ( p_err . argument ) + " arguments. " ;
2020-02-20 03:27:19 +08:00
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ) {
2019-06-18 17:27:43 +08:00
err_text = " Invalid call to " + p_where + " . Expected " + itos ( p_err . argument ) + " arguments. " ;
2020-02-20 03:27:19 +08:00
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) {
2019-06-18 17:27:43 +08:00
err_text = " Invalid call. Nonexistent " + p_where + " . " ;
2020-02-20 03:27:19 +08:00
} else if ( p_err . error = = Callable : : CallError : : CALL_ERROR_INSTANCE_IS_NULL ) {
2019-06-18 17:27:43 +08:00
err_text = " Attempt to call " + p_where + " on a null instance. " ;
} else {
err_text = " Bug, call error: # " + itos ( p_err . error ) ;
}
return err_text ;
}
2016-06-01 09:28:27 +08:00
2017-11-10 00:13:04 +08:00
# if defined(__GNUC__)
2017-09-24 02:06:58 +08:00
# define OPCODES_TABLE \
static const void * switch_table_ops [ ] = { \
& & OPCODE_OPERATOR , \
& & OPCODE_EXTENDS_TEST , \
2018-08-27 00:31:23 +08:00
& & OPCODE_IS_BUILTIN , \
2017-09-24 02:06:58 +08:00
& & OPCODE_SET , \
& & OPCODE_GET , \
& & OPCODE_SET_NAMED , \
& & OPCODE_GET_NAMED , \
& & OPCODE_SET_MEMBER , \
& & OPCODE_GET_MEMBER , \
& & OPCODE_ASSIGN , \
& & OPCODE_ASSIGN_TRUE , \
& & OPCODE_ASSIGN_FALSE , \
2018-05-30 10:16:56 +08:00
& & OPCODE_ASSIGN_TYPED_BUILTIN , \
& & OPCODE_ASSIGN_TYPED_NATIVE , \
& & OPCODE_ASSIGN_TYPED_SCRIPT , \
& & OPCODE_CAST_TO_BUILTIN , \
& & OPCODE_CAST_TO_NATIVE , \
& & OPCODE_CAST_TO_SCRIPT , \
2017-09-24 02:06:58 +08:00
& & OPCODE_CONSTRUCT , \
& & OPCODE_CONSTRUCT_ARRAY , \
& & OPCODE_CONSTRUCT_DICTIONARY , \
& & OPCODE_CALL , \
& & OPCODE_CALL_RETURN , \
2020-05-02 06:14:56 +08:00
& & OPCODE_CALL_ASYNC , \
2017-09-24 02:06:58 +08:00
& & OPCODE_CALL_BUILT_IN , \
& & OPCODE_CALL_SELF , \
& & OPCODE_CALL_SELF_BASE , \
2020-05-02 06:14:56 +08:00
& & OPCODE_AWAIT , \
& & OPCODE_AWAIT_RESUME , \
2017-09-24 02:06:58 +08:00
& & OPCODE_JUMP , \
& & OPCODE_JUMP_IF , \
& & OPCODE_JUMP_IF_NOT , \
& & OPCODE_JUMP_TO_DEF_ARGUMENT , \
& & OPCODE_RETURN , \
& & OPCODE_ITERATE_BEGIN , \
& & OPCODE_ITERATE , \
& & OPCODE_ASSERT , \
& & OPCODE_BREAKPOINT , \
& & OPCODE_LINE , \
& & OPCODE_END \
2020-05-02 06:14:56 +08: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. " ) ;
2017-09-24 02:06:58 +08:00
# define OPCODE(m_op) \
m_op :
# define OPCODE_WHILE(m_test)
# define OPCODES_END \
OPSEXIT :
# define OPCODES_OUT \
OPSOUT :
# define DISPATCH_OPCODE goto *switch_table_ops[_code_ptr[ip]]
# define OPCODE_SWITCH(m_test) DISPATCH_OPCODE;
# 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
# define OPCODE_SWITCH(m_test) switch (m_test)
# define OPCODE_BREAK break
# define OPCODE_OUT break
# endif
2020-02-20 03:27:19 +08:00
Variant GDScriptFunction : : call ( GDScriptInstance * p_instance , const Variant * * p_args , int p_argcount , Callable : : CallError & r_err , CallState * p_state ) {
2017-09-24 02:06:58 +08:00
OPCODES_TABLE ;
2016-06-01 09:28:27 +08:00
if ( ! _code_ptr ) {
return Variant ( ) ;
}
2020-02-20 03:27:19 +08:00
r_err . error = Callable : : CallError : : CALL_OK ;
2016-06-01 09:28:27 +08:00
Variant self ;
2020-02-19 20:15:16 +08:00
Variant static_ref ;
2016-06-01 09:28:27 +08:00
Variant retvalue ;
2020-04-02 07:20:12 +08:00
Variant * stack = nullptr ;
2016-06-01 09:28:27 +08:00
Variant * * call_args ;
2017-03-05 23:44:50 +08:00
int defarg = 0 ;
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
2017-12-07 04:36:34 +08:00
//GDScriptLanguage::get_singleton()->calls++;
2016-06-01 09:28:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
uint32_t alloca_size = 0 ;
2018-10-18 02:36:47 +08:00
GDScript * script ;
2017-03-05 23:44:50 +08:00
int ip = 0 ;
int line = _initial_line ;
2016-06-01 09:28:27 +08:00
if ( p_state ) {
2020-05-02 06:14:56 +08:00
//use existing (supplied) state (awaited)
2017-03-05 23:44:50 +08:00
stack = ( Variant * ) p_state - > stack . ptr ( ) ;
2017-03-21 09:17:17 +08:00
call_args = ( Variant * * ) & p_state - > stack . ptr ( ) [ sizeof ( Variant ) * p_state - > stack_size ] ; //ptr() to avoid bounds check
2017-03-05 23:44:50 +08:00
line = p_state - > line ;
ip = p_state - > ip ;
alloca_size = p_state - > stack . size ( ) ;
2020-05-05 18:53:05 +08:00
script = p_state - > script ;
p_instance = p_state - > instance ;
2017-03-05 23:44:50 +08:00
defarg = p_state - > defarg ;
self = p_state - > self ;
2016-06-01 09:28:27 +08:00
} else {
2017-03-05 23:44:50 +08:00
if ( p_argcount ! = _argument_count ) {
if ( p_argcount > _argument_count ) {
2020-02-20 03:27:19 +08:00
r_err . error = Callable : : CallError : : CALL_ERROR_TOO_MANY_ARGUMENTS ;
2017-03-05 23:44:50 +08:00
r_err . argument = _argument_count ;
2016-06-01 09:28:27 +08:00
return Variant ( ) ;
} else if ( p_argcount < _argument_count - _default_arg_count ) {
2020-02-20 03:27:19 +08:00
r_err . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 23:44:50 +08:00
r_err . argument = _argument_count - _default_arg_count ;
2016-06-01 09:28:27 +08:00
return Variant ( ) ;
} else {
2017-03-05 23:44:50 +08:00
defarg = _argument_count - p_argcount ;
2016-06-01 09:28:27 +08:00
}
}
2017-03-05 23:44:50 +08:00
alloca_size = sizeof ( Variant * ) * _call_size + sizeof ( Variant ) * _stack_size ;
2016-06-01 09:28:27 +08:00
if ( alloca_size ) {
2017-03-05 23:44:50 +08:00
uint8_t * aptr = ( uint8_t * ) alloca ( alloca_size ) ;
2016-06-01 09:28:27 +08:00
if ( _stack_size ) {
2017-03-05 23:44:50 +08:00
stack = ( Variant * ) aptr ;
2018-05-30 10:16:56 +08:00
for ( int i = 0 ; i < p_argcount ; i + + ) {
if ( ! argument_types [ i ] . has_type ) {
memnew_placement ( & stack [ i ] , Variant ( * p_args [ i ] ) ) ;
continue ;
}
2019-03-04 19:25:59 +08:00
if ( ! argument_types [ i ] . is_type ( * p_args [ i ] , true ) ) {
2020-03-27 00:02:28 +08:00
r_err . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
r_err . argument = i ;
r_err . expected = argument_types [ i ] . kind = = GDScriptDataType : : BUILTIN ? argument_types [ i ] . builtin_type : Variant : : OBJECT ;
return Variant ( ) ;
2018-05-30 10:16:56 +08:00
}
2019-03-04 19:25:59 +08:00
if ( argument_types [ i ] . kind = = GDScriptDataType : : BUILTIN ) {
Variant arg = Variant : : construct ( argument_types [ i ] . builtin_type , & p_args [ i ] , 1 , r_err ) ;
memnew_placement ( & stack [ i ] , Variant ( arg ) ) ;
} else {
memnew_placement ( & stack [ i ] , Variant ( * p_args [ i ] ) ) ;
}
2018-05-30 10:16:56 +08:00
}
for ( int i = p_argcount ; i < _stack_size ; i + + ) {
2017-03-05 23:44:50 +08:00
memnew_placement ( & stack [ i ] , Variant ) ;
2018-05-30 10:16:56 +08:00
}
2016-06-01 09:28:27 +08:00
} else {
2020-04-02 07:20:12 +08:00
stack = nullptr ;
2016-06-01 09:28:27 +08:00
}
if ( _call_size ) {
2017-03-05 23:44:50 +08:00
call_args = ( Variant * * ) & aptr [ sizeof ( Variant ) * _stack_size ] ;
2016-06-01 09:28:27 +08:00
} else {
2020-04-02 07:20:12 +08:00
call_args = nullptr ;
2016-06-01 09:28:27 +08:00
}
} else {
2020-04-02 07:20:12 +08:00
stack = nullptr ;
call_args = nullptr ;
2016-06-01 09:28:27 +08:00
}
if ( p_instance ) {
2017-03-05 23:44:50 +08:00
if ( p_instance - > base_ref & & static_cast < Reference * > ( p_instance - > owner ) - > is_referenced ( ) ) {
self = REF ( static_cast < Reference * > ( p_instance - > owner ) ) ;
2016-06-01 09:28:27 +08:00
} else {
2017-03-05 23:44:50 +08:00
self = p_instance - > owner ;
2016-06-01 09:28:27 +08:00
}
2018-10-18 02:36:47 +08:00
script = p_instance - > script . ptr ( ) ;
2016-06-01 09:28:27 +08:00
} else {
2018-11-25 19:38:12 +08:00
script = _script ;
2016-06-01 09:28:27 +08:00
}
}
2020-05-29 21:58:46 +08:00
static_ref = script ;
2016-06-01 09:28:27 +08:00
String err_text ;
# ifdef DEBUG_ENABLED
2020-05-14 22:41:43 +08:00
if ( EngineDebugger : : is_active ( ) ) {
2017-03-05 23:44:50 +08:00
GDScriptLanguage : : get_singleton ( ) - > enter_function ( p_instance , this , stack , & ip , & line ) ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
2017-09-24 02:06:58 +08:00
# 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 ; \
2019-11-11 17:38:15 +08:00
} \
2017-09-24 02:06:58 +08:00
}
2017-09-19 06:06:27 +08:00
2017-03-05 23:44:50 +08:00
# define CHECK_SPACE(m_space) \
2017-09-24 02:06:58 +08:00
GD_ERR_BREAK ( ( ip + m_space ) > _code_size )
2016-06-01 09:28:27 +08:00
2020-02-19 20:15:16 +08:00
# define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant * m_v ; \
m_v = _get_variant ( _code_ptr [ ip + m_code_ofs ] , p_instance , script , self , static_ref , stack , err_text ) ; \
if ( unlikely ( ! m_v ) ) \
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
# else
2017-09-19 06:06:27 +08:00
# define GD_ERR_BREAK(m_cond)
2016-06-01 09:28:27 +08:00
# define CHECK_SPACE(m_space)
2017-03-05 23:44:50 +08:00
# define GET_VARIANT_PTR(m_v, m_code_ofs) \
Variant * m_v ; \
2020-02-19 20:15:16 +08:00
m_v = _get_variant ( _code_ptr [ ip + m_code_ofs ] , p_instance , script , self , static_ref , stack , err_text ) ;
2016-06-01 09:28:27 +08:00
# endif
# ifdef DEBUG_ENABLED
2017-09-02 04:33:39 +08:00
uint64_t function_start_time = 0 ;
uint64_t function_call_time = 0 ;
2016-06-01 09:28:27 +08:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
2017-03-05 23:44:50 +08:00
function_start_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
function_call_time = 0 ;
2016-06-01 09:28:27 +08:00
profile . call_count + + ;
profile . frame_call_count + + ;
}
2017-03-05 23:44:50 +08:00
bool exit_ok = false ;
2020-05-02 06:14:56 +08:00
bool awaited = false ;
2018-10-06 20:41:31 +08:00
# endif
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2017-09-24 02:06:58 +08:00
OPCODE_WHILE ( ip < _code_size ) {
2017-03-05 23:44:50 +08:00
int last_opcode = _code_ptr [ ip ] ;
2017-09-19 06:06:27 +08:00
# else
2017-09-24 02:06:58 +08:00
OPCODE_WHILE ( true ) {
2017-09-19 06:06:27 +08:00
# endif
2017-09-24 02:06:58 +08:00
OPCODE_SWITCH ( _code_ptr [ ip ] ) {
OPCODE ( OPCODE_OPERATOR ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 5 ) ;
bool valid ;
2017-03-05 23:44:50 +08:00
Variant : : Operator op = ( Variant : : Operator ) _code_ptr [ ip + 1 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( op > = Variant : : OP_MAX ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( a , 2 ) ;
GET_VARIANT_PTR ( b , 3 ) ;
GET_VARIANT_PTR ( dst , 4 ) ;
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
2017-09-19 06:06:27 +08:00
2016-06-01 09:28:27 +08:00
Variant ret ;
2017-03-05 23:44:50 +08:00
Variant : : evaluate ( op , * a , * b , ret , valid ) ;
2016-06-01 09:28:27 +08:00
# else
2017-03-05 23:44:50 +08:00
Variant : : evaluate ( op , * a , * b , * dst , valid ) ;
2016-06-01 09:28:27 +08:00
# endif
# ifdef DEBUG_ENABLED
2017-09-19 06:06:27 +08:00
if ( ! valid ) {
2017-03-05 23:44:50 +08:00
if ( ret . get_type ( ) = = Variant : : STRING ) {
2016-06-01 09:28:27 +08:00
//return a string when invalid with the error
2017-03-05 23:44:50 +08:00
err_text = ret ;
err_text + = " in operator ' " + Variant : : get_operator_name ( op ) + " '. " ;
2016-06-01 09:28:27 +08:00
} else {
2017-03-05 23:44:50 +08:00
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 ) + " '. " ;
2016-06-01 09:28:27 +08:00
}
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
* dst = ret ;
2016-06-01 09:28:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
ip + = 5 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_EXTENDS_TEST ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 4 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( a , 1 ) ;
GET_VARIANT_PTR ( b , 2 ) ;
GET_VARIANT_PTR ( dst , 3 ) ;
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
2020-04-02 07:20:12 +08:00
if ( b - > get_type ( ) ! = Variant : : OBJECT | | b - > operator Object * ( ) = = nullptr ) {
2017-05-27 01:45:39 +08:00
err_text = " Right operand of 'is' is not a class. " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
# endif
2017-03-05 23:44:50 +08:00
bool extends_ok = false ;
2020-04-02 07:20:12 +08:00
if ( a - > get_type ( ) = = Variant : : OBJECT & & a - > operator Object * ( ) ! = nullptr ) {
2020-01-10 00:59:33 +08:00
# ifdef DEBUG_ENABLED
2020-02-14 03:03:10 +08:00
bool was_freed ;
Object * obj_A = a - > get_validated_object_with_check ( was_freed ) ;
if ( was_freed ) {
err_text = " Left operand of 'is' is a previously freed instance. " ;
2020-01-10 00:59:33 +08:00
OPCODE_BREAK ;
}
2020-02-14 03:03:10 +08:00
Object * obj_B = b - > get_validated_object_with_check ( was_freed ) ;
if ( was_freed ) {
err_text = " Right operand of 'is' is a previously freed instance. " ;
OPCODE_BREAK ;
}
# else
Object * obj_A = * a ;
Object * obj_B = * b ;
2020-01-10 00:59:33 +08:00
# endif // DEBUG_ENABLED
2018-11-18 08:41:08 +08:00
GDScript * scr_B = Object : : cast_to < GDScript > ( obj_B ) ;
2016-06-01 09:28:27 +08:00
2018-11-18 08:41:08 +08:00
if ( scr_B ) {
//if B is a script, the only valid condition is that A has an instance which inherits from the script
//in other situation, this shoul return false.
2016-06-01 09:28:27 +08:00
2018-11-18 08:41:08 +08:00
if ( obj_A - > get_script_instance ( ) & & obj_A - > get_script_instance ( ) - > get_language ( ) = = GDScriptLanguage : : get_singleton ( ) ) {
GDScript * cmp = static_cast < GDScript * > ( obj_A - > get_script_instance ( ) - > get_script ( ) . ptr ( ) ) ;
//bool found=false;
while ( cmp ) {
if ( cmp = = scr_B ) {
//inherits from script, all ok
extends_ok = true ;
break ;
}
2016-06-01 09:28:27 +08:00
2018-11-18 08:41:08 +08:00
cmp = cmp - > _base ;
}
2016-06-01 09:28:27 +08:00
}
2018-11-18 08:41:08 +08:00
} else {
GDScriptNativeClass * nc = Object : : cast_to < GDScriptNativeClass > ( obj_B ) ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2018-11-18 08:41:08 +08:00
if ( ! nc ) {
err_text = " Right operand of 'is' is not a class (type: ' " + obj_B - > get_class ( ) + " '). " ;
OPCODE_BREAK ;
}
2017-09-19 06:06:27 +08:00
# endif
2018-11-18 08:41:08 +08:00
extends_ok = ClassDB : : is_parent_class ( obj_A - > get_class_name ( ) , nc - > get_name ( ) ) ;
}
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
* dst = extends_ok ;
ip + = 4 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2018-08-27 00:31:23 +08:00
OPCODE ( OPCODE_IS_BUILTIN ) {
CHECK_SPACE ( 4 ) ;
GET_VARIANT_PTR ( value , 1 ) ;
Variant : : Type var_type = ( Variant : : Type ) _code_ptr [ ip + 2 ] ;
GET_VARIANT_PTR ( dst , 3 ) ;
GD_ERR_BREAK ( var_type < 0 | | var_type > = Variant : : VARIANT_MAX ) ;
* dst = value - > get_type ( ) = = var_type ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_SET ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 1 ) ;
GET_VARIANT_PTR ( index , 2 ) ;
GET_VARIANT_PTR ( value , 3 ) ;
2016-06-01 09:28:27 +08:00
bool valid ;
2017-03-05 23:44:50 +08:00
dst - > set ( * index , * value , & valid ) ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
if ( ! valid ) {
String v = index - > operator String ( ) ;
2017-03-05 23:44:50 +08:00
if ( v ! = " " ) {
v = " ' " + v + " ' " ;
2016-06-01 09:28:27 +08:00
} else {
2017-03-05 23:44:50 +08:00
v = " of type ' " + _get_var_type ( index ) + " ' " ;
2016-06-01 09:28:27 +08:00
}
2017-12-10 08:27:02 +08:00
err_text = " Invalid set index " + v + " (on base: ' " + _get_var_type ( dst ) + " ') with value of type ' " + _get_var_type ( value ) + " ' " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
ip + = 4 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_GET ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( src , 1 ) ;
GET_VARIANT_PTR ( index , 2 ) ;
GET_VARIANT_PTR ( dst , 3 ) ;
2016-06-01 09:28:27 +08:00
bool valid ;
# ifdef DEBUG_ENABLED
//allow better error message in cases where src and dst are the same stack position
2017-03-05 23:44:50 +08:00
Variant ret = src - > get ( * index , & valid ) ;
2016-06-01 09:28:27 +08:00
# else
2017-03-05 23:44:50 +08:00
* dst = src - > get ( * index , & valid ) ;
2016-06-01 09:28:27 +08:00
# endif
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
if ( ! valid ) {
String v = index - > operator String ( ) ;
2017-03-05 23:44:50 +08:00
if ( v ! = " " ) {
v = " ' " + v + " ' " ;
2016-06-01 09:28:27 +08:00
} else {
2017-03-05 23:44:50 +08:00
v = " of type ' " + _get_var_type ( index ) + " ' " ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
err_text = " Invalid get index " + v + " (on base: ' " + _get_var_type ( src ) + " '). " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
* dst = ret ;
2016-06-01 09:28:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
ip + = 4 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_SET_NAMED ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 1 ) ;
GET_VARIANT_PTR ( value , 3 ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
int indexname = _code_ptr [ ip + 2 ] ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
2016-06-01 09:28:27 +08:00
const StringName * index = & _global_names_ptr [ indexname ] ;
bool valid ;
2017-03-05 23:44:50 +08:00
dst - > set_named ( * index , * value , & valid ) ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
if ( ! valid ) {
String err_type ;
2017-12-10 08:27:02 +08:00
err_text = " Invalid set index ' " + String ( * index ) + " ' (on base: ' " + _get_var_type ( dst ) + " ') with value of type ' " + _get_var_type ( value ) + " '. " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
ip + = 4 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_GET_NAMED ) {
2017-01-05 04:37:45 +08:00
CHECK_SPACE ( 4 ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( src , 1 ) ;
GET_VARIANT_PTR ( dst , 3 ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
int indexname = _code_ptr [ ip + 2 ] ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
2016-06-01 09:28:27 +08:00
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
2017-03-05 23:44:50 +08:00
Variant ret = src - > get_named ( * index , & valid ) ;
2016-06-01 09:28:27 +08:00
# else
2017-03-05 23:44:50 +08:00
* dst = src - > get_named ( * index , & valid ) ;
2016-06-01 09:28:27 +08:00
# endif
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
if ( ! valid ) {
if ( src - > has_method ( * index ) ) {
2017-12-27 06:16:41 +08:00
err_text = " Invalid get index ' " + index - > operator String ( ) + " ' (on base: ' " + _get_var_type ( src ) + " '). Did you mean '. " + index - > operator String ( ) + " ()' or funcref(obj, \" " + index - > operator String ( ) + " \" ) ? " ;
2016-06-01 09:28:27 +08:00
} else {
2017-03-05 23:44:50 +08:00
err_text = " Invalid get index ' " + index - > operator String ( ) + " ' (on base: ' " + _get_var_type ( src ) + " '). " ;
2016-06-01 09:28:27 +08:00
}
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
* dst = ret ;
2016-06-01 09:28:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
ip + = 4 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_SET_MEMBER ) {
2017-01-05 04:37:45 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
int indexname = _code_ptr [ ip + 1 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
2017-01-05 04:37:45 +08:00
const StringName * index = & _global_names_ptr [ indexname ] ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( src , 2 ) ;
2017-01-05 04:37:45 +08:00
bool valid ;
2018-10-06 20:41:31 +08:00
# ifndef DEBUG_ENABLED
ClassDB : : set_property ( p_instance - > owner , * index , * src , & valid ) ;
# else
2017-03-05 23:44:50 +08:00
bool ok = ClassDB : : set_property ( p_instance - > owner , * index , * src , & valid ) ;
2017-01-05 04:37:45 +08:00
if ( ! ok ) {
2017-03-05 23:44:50 +08:00
err_text = " Internal error setting property: " + String ( * index ) ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2017-01-05 04:37:45 +08:00
} else if ( ! valid ) {
2017-03-05 23:44:50 +08:00
err_text = " Error setting property ' " + String ( * index ) + " ' with value of type " + Variant : : get_type_name ( src - > get_type ( ) ) + " . " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2017-01-05 04:37:45 +08:00
}
# endif
2017-03-05 23:44:50 +08:00
ip + = 3 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_GET_MEMBER ) {
2017-01-05 04:37:45 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
int indexname = _code_ptr [ ip + 1 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( indexname < 0 | | indexname > = _global_names_count ) ;
2017-01-05 04:37:45 +08:00
const StringName * index = & _global_names_ptr [ indexname ] ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 2 ) ;
2018-10-06 18:30:45 +08:00
2018-10-06 20:41:31 +08:00
# ifndef DEBUG_ENABLED
ClassDB : : get_property ( p_instance - > owner , * index , * dst ) ;
# else
bool ok = ClassDB : : get_property ( p_instance - > owner , * index , * dst ) ;
2017-01-05 04:37:45 +08:00
if ( ! ok ) {
2017-03-05 23:44:50 +08:00
err_text = " Internal error getting property: " + String ( * index ) ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2017-01-05 04:37:45 +08:00
}
# endif
2017-03-05 23:44:50 +08:00
ip + = 3 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_ASSIGN ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 1 ) ;
GET_VARIANT_PTR ( src , 2 ) ;
2016-06-01 09:28:27 +08:00
* dst = * src ;
2017-03-05 23:44:50 +08:00
ip + = 3 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_ASSIGN_TRUE ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 1 ) ;
2016-06-01 09:28:27 +08:00
* dst = true ;
2017-03-05 23:44:50 +08:00
ip + = 2 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_ASSIGN_FALSE ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 1 ) ;
2016-06-01 09:28:27 +08:00
* dst = false ;
2017-03-05 23:44:50 +08:00
ip + = 2 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2018-05-30 10:16:56 +08:00
OPCODE ( OPCODE_ASSIGN_TYPED_BUILTIN ) {
CHECK_SPACE ( 4 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
GET_VARIANT_PTR ( src , 3 ) ;
2018-10-06 20:41:31 +08:00
Variant : : Type var_type = ( Variant : : Type ) _code_ptr [ ip + 1 ] ;
2018-05-30 10:16:56 +08:00
GD_ERR_BREAK ( var_type < 0 | | var_type > = Variant : : VARIANT_MAX ) ;
if ( src - > get_type ( ) ! = var_type ) {
2019-12-13 22:35:01 +08:00
# ifdef DEBUG_ENABLED
2018-07-26 00:12:07 +08:00
if ( Variant : : can_convert_strict ( src - > get_type ( ) , var_type ) ) {
2019-12-13 22:35:01 +08:00
# endif // DEBUG_ENABLED
2020-02-20 03:27:19 +08:00
Callable : : CallError ce ;
2018-07-26 00:12:07 +08:00
* dst = Variant : : construct ( var_type , const_cast < const Variant * * > ( & src ) , 1 , ce ) ;
} else {
2019-12-13 22:35:01 +08:00
# ifdef DEBUG_ENABLED
2018-07-26 00:12:07 +08:00
err_text = " Trying to assign value of type ' " + Variant : : get_type_name ( src - > get_type ( ) ) +
" ' to a variable of type ' " + Variant : : get_type_name ( var_type ) + " '. " ;
OPCODE_BREAK ;
}
} else {
2018-07-26 05:45:38 +08:00
# endif // DEBUG_ENABLED
2018-07-26 00:12:07 +08:00
* dst = * src ;
2018-05-30 10:16:56 +08:00
}
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ASSIGN_TYPED_NATIVE ) {
CHECK_SPACE ( 4 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
GET_VARIANT_PTR ( src , 3 ) ;
2018-07-26 05:45:38 +08:00
# ifdef DEBUG_ENABLED
2018-10-06 20:41:31 +08:00
GET_VARIANT_PTR ( type , 1 ) ;
2018-05-30 10:16:56 +08:00
GDScriptNativeClass * nc = Object : : cast_to < GDScriptNativeClass > ( type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! nc ) ;
2018-09-27 16:43:12 +08:00
if ( src - > get_type ( ) ! = Variant : : OBJECT & & src - > get_type ( ) ! = Variant : : NIL ) {
2018-07-26 05:45:38 +08:00
err_text = " Trying to assign value of type ' " + Variant : : get_type_name ( src - > get_type ( ) ) +
" ' to a variable of type ' " + nc - > get_name ( ) + " '. " ;
OPCODE_BREAK ;
}
2018-05-30 10:16:56 +08:00
Object * src_obj = src - > operator Object * ( ) ;
2018-07-26 05:45:38 +08:00
if ( src_obj & & ! ClassDB : : is_parent_class ( src_obj - > get_class_name ( ) , nc - > get_name ( ) ) ) {
2018-05-30 10:16:56 +08:00
err_text = " Trying to assign value of type ' " + src_obj - > get_class_name ( ) +
" ' to a variable of type ' " + nc - > get_name ( ) + " '. " ;
OPCODE_BREAK ;
}
2018-07-26 05:45:38 +08:00
# endif // DEBUG_ENABLED
2018-05-30 10:16:56 +08:00
* dst = * src ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_ASSIGN_TYPED_SCRIPT ) {
CHECK_SPACE ( 4 ) ;
GET_VARIANT_PTR ( dst , 2 ) ;
GET_VARIANT_PTR ( src , 3 ) ;
2018-07-26 05:45:38 +08:00
# ifdef DEBUG_ENABLED
2018-10-06 20:41:31 +08:00
GET_VARIANT_PTR ( type , 1 ) ;
2018-05-30 10:16:56 +08: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 ;
}
2020-04-02 07:20:12 +08:00
if ( src - > get_type ( ) ! = Variant : : NIL & & src - > operator Object * ( ) ! = nullptr ) {
2018-05-30 10:16:56 +08:00
ScriptInstance * scr_inst = src - > operator Object * ( ) - > get_script_instance ( ) ;
if ( ! scr_inst ) {
err_text = " Trying to assign value of type ' " + src - > operator Object * ( ) - > get_class_name ( ) +
" ' to a variable of type ' " + base_type - > get_path ( ) . get_file ( ) + " '. " ;
OPCODE_BREAK ;
}
Script * src_type = src - > operator Object * ( ) - > get_script_instance ( ) - > 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 ' " + src - > operator Object * ( ) - > get_script_instance ( ) - > get_script ( ) - > get_path ( ) . get_file ( ) +
" ' to a variable of type ' " + base_type - > get_path ( ) . get_file ( ) + " '. " ;
OPCODE_BREAK ;
}
}
2018-07-26 05:45:38 +08:00
# endif // DEBUG_ENABLED
2018-05-30 10:16:56 +08:00
* dst = * src ;
ip + = 4 ;
}
DISPATCH_OPCODE ;
OPCODE ( OPCODE_CAST_TO_BUILTIN ) {
CHECK_SPACE ( 4 ) ;
Variant : : Type to_type = ( Variant : : Type ) _code_ptr [ ip + 1 ] ;
GET_VARIANT_PTR ( src , 2 ) ;
GET_VARIANT_PTR ( dst , 3 ) ;
GD_ERR_BREAK ( to_type < 0 | | to_type > = Variant : : VARIANT_MAX ) ;
2020-02-20 03:27:19 +08:00
Callable : : CallError err ;
2018-05-30 10:16:56 +08:00
* dst = Variant : : construct ( to_type , ( const Variant * * ) & src , 1 , err ) ;
# ifdef DEBUG_ENABLED
2020-02-20 03:27:19 +08:00
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
2018-05-30 10:16:56 +08:00
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 ) ;
GET_VARIANT_PTR ( to_type , 1 ) ;
GET_VARIANT_PTR ( src , 2 ) ;
GET_VARIANT_PTR ( dst , 3 ) ;
GDScriptNativeClass * nc = Object : : cast_to < GDScriptNativeClass > ( to_type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! nc ) ;
# ifdef DEBUG_ENABLED
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 ) ;
GET_VARIANT_PTR ( to_type , 1 ) ;
GET_VARIANT_PTR ( src , 2 ) ;
GET_VARIANT_PTR ( dst , 3 ) ;
Script * base_type = Object : : cast_to < Script > ( to_type - > operator Object * ( ) ) ;
GD_ERR_BREAK ( ! base_type ) ;
# ifdef DEBUG_ENABLED
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 ;
2020-04-02 07:20:12 +08:00
if ( src - > get_type ( ) ! = Variant : : NIL & & src - > operator Object * ( ) ! = nullptr ) {
2018-05-30 10:16:56 +08:00
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 ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_CONSTRUCT ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
Variant : : Type t = Variant : : Type ( _code_ptr [ ip + 1 ] ) ;
int argc = _code_ptr [ ip + 2 ] ;
CHECK_SPACE ( argc + 2 ) ;
2016-06-01 09:28:27 +08:00
Variant * * argptrs = call_args ;
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < argc ; i + + ) {
GET_VARIANT_PTR ( v , 3 + i ) ;
argptrs [ i ] = v ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 3 + argc ) ;
2020-02-20 03:27:19 +08:00
Callable : : CallError err ;
2017-03-05 23:44:50 +08:00
* dst = Variant : : construct ( t , ( const Variant * * ) argptrs , argc , err ) ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2020-02-20 03:27:19 +08:00
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
2017-03-05 23:44:50 +08:00
err_text = _get_call_error ( err , " ' " + Variant : : get_type_name ( t ) + " ' constructor " , ( const Variant * * ) argptrs ) ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
ip + = 4 + argc ;
2016-06-01 09:28:27 +08:00
//construct a basic type
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_CONSTRUCT_ARRAY ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 1 ) ;
2017-03-05 23:44:50 +08:00
int argc = _code_ptr [ ip + 1 ] ;
2017-01-11 19:53:31 +08:00
Array array ; //arrays are always shared
2016-06-01 09:28:27 +08:00
array . resize ( argc ) ;
2017-03-05 23:44:50 +08:00
CHECK_SPACE ( argc + 2 ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < argc ; i + + ) {
GET_VARIANT_PTR ( v , 2 + i ) ;
array [ i ] = * v ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 2 + argc ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
* dst = array ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
ip + = 3 + argc ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_CONSTRUCT_DICTIONARY ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 1 ) ;
2017-03-05 23:44:50 +08:00
int argc = _code_ptr [ ip + 1 ] ;
2017-01-11 19:53:31 +08:00
Dictionary dict ; //arrays are always shared
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
CHECK_SPACE ( argc * 2 + 2 ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < argc ; i + + ) {
GET_VARIANT_PTR ( k , 2 + i * 2 + 0 ) ;
GET_VARIANT_PTR ( v , 2 + i * 2 + 1 ) ;
dict [ * k ] = * v ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , 2 + argc * 2 ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
* dst = dict ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
ip + = 3 + argc * 2 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2020-05-02 06:14:56 +08:00
OPCODE ( OPCODE_CALL_ASYNC )
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_CALL_RETURN )
OPCODE ( OPCODE_CALL ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 4 ) ;
2020-05-02 06:14:56 +08:00
bool call_ret = _code_ptr [ ip ] ! = OPCODE_CALL ;
# ifdef DEBUG_ENABLED
bool call_async = _code_ptr [ ip ] = = OPCODE_CALL_ASYNC ;
# endif
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
int argc = _code_ptr [ ip + 1 ] ;
GET_VARIANT_PTR ( base , 2 ) ;
int nameg = _code_ptr [ ip + 3 ] ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( nameg < 0 | | nameg > = _global_names_count ) ;
2016-06-01 09:28:27 +08:00
const StringName * methodname = & _global_names_ptr [ nameg ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( argc < 0 ) ;
2017-03-05 23:44:50 +08:00
ip + = 4 ;
CHECK_SPACE ( argc + 1 ) ;
2016-06-01 09:28:27 +08:00
Variant * * argptrs = call_args ;
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < argc ; i + + ) {
GET_VARIANT_PTR ( v , i ) ;
argptrs [ i ] = v ;
2016-06-01 09:28:27 +08:00
}
# ifdef DEBUG_ENABLED
2017-09-02 04:33:39 +08:00
uint64_t call_time = 0 ;
2016-06-01 09:28:27 +08:00
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
2017-03-05 23:44:50 +08:00
call_time = OS : : get_singleton ( ) - > get_ticks_usec ( ) ;
2016-06-01 09:28:27 +08:00
}
# endif
2020-02-20 03:27:19 +08:00
Callable : : CallError err ;
2016-06-01 09:28:27 +08:00
if ( call_ret ) {
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( ret , argc ) ;
base - > call_ptr ( * methodname , ( const Variant * * ) argptrs , argc , ret , err ) ;
2020-05-02 06:14:56 +08:00
# ifdef DEBUG_ENABLED
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 ( was_freed ) {
err_text = " Got a freed object as a result of the call. " ;
OPCODE_BREAK ;
}
if ( obj - > is_class_ptr ( GDScriptFunctionState : : get_class_ptr_static ( ) ) ) {
err_text = R " (Trying to call an async function without " await " .) " ;
OPCODE_BREAK ;
}
}
# endif
2016-06-01 09:28:27 +08:00
} else {
2020-04-02 07:20:12 +08:00
base - > call_ptr ( * methodname , ( const Variant * * ) argptrs , argc , nullptr , err ) ;
2016-06-01 09:28:27 +08:00
}
# ifdef DEBUG_ENABLED
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
2017-03-05 23:44:50 +08:00
function_call_time + = OS : : get_singleton ( ) - > get_ticks_usec ( ) - call_time ;
2016-06-01 09:28:27 +08:00
}
2020-02-20 03:27:19 +08:00
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
2016-06-01 09:28:27 +08:00
String methodstr = * methodname ;
String basestr = _get_var_type ( base ) ;
2017-03-05 23:44:50 +08:00
if ( methodstr = = " call " ) {
if ( argc > = 1 ) {
methodstr = String ( * argptrs [ 0 ] ) + " (via call) " ;
2020-02-20 03:27:19 +08:00
if ( err . error = = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ) {
2019-01-31 23:02:18 +08:00
err . argument + = 1 ;
2016-06-01 09:28:27 +08:00
}
}
2017-03-05 23:44:50 +08:00
} else if ( methodstr = = " free " ) {
2020-02-20 03:27:19 +08:00
if ( err . error = = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ) {
2016-06-01 09:28:27 +08:00
if ( base - > is_ref ( ) ) {
2017-03-05 23:44:50 +08:00
err_text = " Attempted to free a reference. " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2017-03-05 23:44:50 +08:00
} else if ( base - > get_type ( ) = = Variant : : OBJECT ) {
err_text = " Attempted to free a locked object (calling or emitting). " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
}
}
2017-03-05 23:44:50 +08:00
err_text = _get_call_error ( err , " function ' " + methodstr + " ' in base ' " + basestr + " ' " , ( const Variant * * ) argptrs ) ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2016-06-01 09:28:27 +08:00
2020-04-02 07:20:12 +08:00
//_call_func(nullptr,base,*methodname,ip,argc,p_instance,stack);
2017-03-05 23:44:50 +08:00
ip + = argc + 1 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_CALL_BUILT_IN ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 4 ) ;
2017-11-17 01:38:18 +08:00
GDScriptFunctions : : Function func = GDScriptFunctions : : Function ( _code_ptr [ ip + 1 ] ) ;
2017-03-05 23:44:50 +08:00
int argc = _code_ptr [ ip + 2 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( argc < 0 ) ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
ip + = 3 ;
CHECK_SPACE ( argc + 1 ) ;
2016-06-01 09:28:27 +08:00
Variant * * argptrs = call_args ;
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < argc ; i + + ) {
GET_VARIANT_PTR ( v , i ) ;
argptrs [ i ] = v ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , argc ) ;
2016-06-01 09:28:27 +08:00
2020-02-20 03:27:19 +08:00
Callable : : CallError err ;
2016-06-01 09:28:27 +08:00
2017-11-17 01:38:18 +08:00
GDScriptFunctions : : call ( func , ( const Variant * * ) argptrs , argc , * dst , err ) ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2020-02-20 03:27:19 +08:00
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
2017-11-17 01:38:18 +08:00
String methodstr = GDScriptFunctions : : get_func_name ( func ) ;
2017-03-05 23:44:50 +08:00
if ( dst - > get_type ( ) = = Variant : : STRING ) {
2016-06-12 06:43:38 +08:00
//call provided error string
2017-03-05 23:44:50 +08:00
err_text = " Error calling built-in function ' " + methodstr + " ': " + String ( * dst ) ;
2016-06-12 06:43:38 +08:00
} else {
2017-03-05 23:44:50 +08:00
err_text = _get_call_error ( err , " built-in function ' " + methodstr + " ' " , ( const Variant * * ) argptrs ) ;
2016-06-12 06:43:38 +08:00
}
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
ip + = argc + 1 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_CALL_SELF ) {
OPCODE_BREAK ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_CALL_SELF_BASE ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
int self_fun = _code_ptr [ ip + 1 ] ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2017-03-05 23:44:50 +08:00
if ( self_fun < 0 | | self_fun > = _global_names_count ) {
err_text = " compiler bug, function name not found " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
# endif
const StringName * methodname = & _global_names_ptr [ self_fun ] ;
2017-03-05 23:44:50 +08:00
int argc = _code_ptr [ ip + 2 ] ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
CHECK_SPACE ( 2 + argc + 1 ) ;
2016-06-01 09:28:27 +08:00
Variant * * argptrs = call_args ;
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < argc ; i + + ) {
GET_VARIANT_PTR ( v , i + 3 ) ;
argptrs [ i ] = v ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( dst , argc + 3 ) ;
2016-06-01 09:28:27 +08:00
2018-11-25 06:46:13 +08:00
const GDScript * gds = _script ;
2016-06-01 09:28:27 +08:00
2020-04-02 07:20:12 +08:00
const Map < StringName , GDScriptFunction * > : : Element * E = nullptr ;
2016-06-01 09:28:27 +08:00
while ( gds - > base . ptr ( ) ) {
2017-03-05 23:44:50 +08:00
gds = gds - > base . ptr ( ) ;
E = gds - > member_functions . find ( * methodname ) ;
2020-05-14 22:41:43 +08:00
if ( E ) {
2017-09-27 09:23:39 +08:00
break ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
}
2020-02-20 03:27:19 +08:00
Callable : : CallError err ;
2016-06-01 09:28:27 +08:00
if ( E ) {
2017-03-05 23:44:50 +08:00
* dst = E - > get ( ) - > call ( p_instance , ( const Variant * * ) argptrs , argc , err ) ;
2016-06-01 09:28:27 +08:00
} else if ( gds - > native . ptr ( ) ) {
2017-03-05 23:44:50 +08:00
if ( * methodname ! = GDScriptLanguage : : get_singleton ( ) - > strings . _init ) {
MethodBind * mb = ClassDB : : get_method ( gds - > native - > get_name ( ) , * methodname ) ;
2016-06-01 09:28:27 +08:00
if ( ! mb ) {
2020-02-20 03:27:19 +08:00
err . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2016-06-01 09:28:27 +08:00
} else {
2017-03-05 23:44:50 +08:00
* dst = mb - > call ( p_instance - > owner , ( const Variant * * ) argptrs , argc , err ) ;
2016-06-01 09:28:27 +08:00
}
} else {
2020-02-20 03:27:19 +08:00
err . error = Callable : : CallError : : CALL_OK ;
2016-06-01 09:28:27 +08:00
}
} else {
2017-03-05 23:44:50 +08:00
if ( * methodname ! = GDScriptLanguage : : get_singleton ( ) - > strings . _init ) {
2020-02-20 03:27:19 +08:00
err . error = Callable : : CallError : : CALL_ERROR_INVALID_METHOD ;
2016-06-01 09:28:27 +08:00
} else {
2020-02-20 03:27:19 +08:00
err . error = Callable : : CallError : : CALL_OK ;
2016-06-01 09:28:27 +08:00
}
}
2020-02-20 03:27:19 +08:00
if ( err . error ! = Callable : : CallError : : CALL_OK ) {
2016-06-01 09:28:27 +08:00
String methodstr = * methodname ;
2017-03-05 23:44:50 +08:00
err_text = _get_call_error ( err , " function ' " + methodstr + " ' " , ( const Variant * * ) argptrs ) ;
2016-06-01 09:28:27 +08:00
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
ip + = 4 + argc ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2020-05-02 06:14:56 +08:00
OPCODE ( OPCODE_AWAIT ) {
int ipofs = 2 ;
CHECK_SPACE ( 3 ) ;
2016-06-01 09:28:27 +08:00
2020-05-02 06:14:56 +08:00
//do the oneshot connect
GET_VARIANT_PTR ( argobj , 1 ) ;
Signal sig ;
bool is_signal = true ;
2016-06-01 09:28:27 +08:00
2020-05-05 18:53:05 +08:00
{
2020-05-02 06:14:56 +08:00
Variant result = * argobj ;
2016-06-01 09:28:27 +08:00
2020-05-02 06:14:56 +08:00
if ( argobj - > get_type ( ) = = Variant : : OBJECT ) {
bool was_freed = false ;
Object * obj = argobj - > get_validated_object_with_check ( was_freed ) ;
2016-06-01 09:28:27 +08:00
2020-05-02 06:14:56 +08:00
if ( was_freed ) {
err_text = " Trying to await on a freed object. " ;
OPCODE_BREAK ;
}
2016-06-01 09:28:27 +08:00
2020-05-02 06:14:56 +08:00
// Is this even possible to be null at this point?
if ( obj ) {
if ( obj - > is_class_ptr ( GDScriptFunctionState : : get_class_ptr_static ( ) ) ) {
static StringName completed = _scs_create ( " completed " ) ;
result = Signal ( obj , completed ) ;
}
}
2016-06-01 09:28:27 +08:00
}
2018-10-03 22:13:34 +08:00
2020-05-02 06:14:56 +08:00
if ( result . get_type ( ) ! = Variant : : SIGNAL ) {
ip + = 4 ; // Skip OPCODE_AWAIT_RESUME and its data.
// The stack pointer should be the same, so we don't need to set a return value.
is_signal = false ;
} else {
sig = result ;
2020-02-14 03:03:10 +08:00
}
2020-05-02 06:14:56 +08:00
}
2020-02-14 03:03:10 +08:00
2020-05-02 06:14:56 +08:00
if ( is_signal ) {
Ref < GDScriptFunctionState > gdfs = memnew ( GDScriptFunctionState ) ;
gdfs - > function = this ;
gdfs - > state . stack . resize ( alloca_size ) ;
//copy variant stack
for ( int i = 0 ; i < _stack_size ; i + + ) {
memnew_placement ( & gdfs - > state . stack . write [ sizeof ( Variant ) * i ] , Variant ( stack [ i ] ) ) ;
2016-06-01 09:28:27 +08:00
}
2020-05-02 06:14:56 +08:00
gdfs - > state . stack_size = _stack_size ;
gdfs - > state . self = self ;
gdfs - > state . alloca_size = alloca_size ;
gdfs - > state . ip = ip + ipofs ;
gdfs - > state . line = line ;
gdfs - > state . script = _script ;
{
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > lock ) ;
_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 ;
}
2016-06-01 09:28:27 +08:00
}
2020-05-02 06:14:56 +08:00
# ifdef DEBUG_ENABLED
gdfs - > state . function_name = name ;
gdfs - > state . script_path = _script - > get_path ( ) ;
# endif
gdfs - > state . defarg = defarg ;
gdfs - > function = this ;
2016-06-01 09:28:27 +08:00
2020-05-02 06:14:56 +08:00
retvalue = gdfs ;
Error err = sig . connect ( Callable ( gdfs . ptr ( ) , " _signal_callback " ) , varray ( gdfs ) , Object : : CONNECT_ONESHOT ) ;
2017-03-05 23:44:50 +08:00
if ( err ! = OK ) {
2020-05-02 06:14:56 +08:00
err_text = " Error connecting to signal: " + sig . get_name ( ) + " during await. " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2018-10-06 20:41:31 +08:00
# ifdef DEBUG_ENABLED
2020-05-02 06:14:56 +08:00
exit_ok = true ;
awaited = true ;
2018-10-06 20:41:31 +08:00
# endif
2020-05-02 06:14:56 +08:00
OPCODE_BREAK ;
}
2017-01-15 23:38:54 +08:00
}
2020-05-02 06:14:56 +08:00
DISPATCH_OPCODE ; // Needed for synchronous calls (when result is immediately available).
2017-11-10 00:13:04 +08:00
2020-05-02 06:14:56 +08:00
OPCODE ( OPCODE_AWAIT_RESUME ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
if ( ! p_state ) {
2017-03-05 23:44:50 +08:00
err_text = ( " Invalid Resume (bug?) " ) ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( result , 1 ) ;
* result = p_state - > result ;
ip + = 2 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_JUMP ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
int to = _code_ptr [ ip + 1 ] ;
2016-06-01 09:28:27 +08:00
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( to < 0 | | to > _code_size ) ;
2017-03-05 23:44:50 +08:00
ip = to ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_JUMP_IF ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( test , 1 ) ;
2016-06-01 09:28:27 +08:00
2017-09-19 02:02:47 +08:00
bool result = test - > booleanize ( ) ;
2016-06-01 09:28:27 +08:00
if ( result ) {
2017-03-05 23:44:50 +08:00
int to = _code_ptr [ ip + 2 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( to < 0 | | to > _code_size ) ;
2017-03-05 23:44:50 +08:00
ip = to ;
2017-11-10 00:13:04 +08:00
} else {
ip + = 3 ;
2016-06-01 09:28:27 +08:00
}
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_JUMP_IF_NOT ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 3 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( test , 1 ) ;
2016-06-01 09:28:27 +08:00
2017-09-19 02:02:47 +08:00
bool result = test - > booleanize ( ) ;
2016-06-01 09:28:27 +08:00
if ( ! result ) {
2017-03-05 23:44:50 +08:00
int to = _code_ptr [ ip + 2 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( to < 0 | | to > _code_size ) ;
2017-03-05 23:44:50 +08:00
ip = to ;
2017-11-10 00:13:04 +08:00
} else {
ip + = 3 ;
2016-06-01 09:28:27 +08:00
}
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_JUMP_TO_DEF_ARGUMENT ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
ip = _default_arg_ptr [ defarg ] ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_RETURN ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( r , 1 ) ;
retvalue = * r ;
2018-10-06 20:41:31 +08:00
# ifdef DEBUG_ENABLED
2017-03-05 23:44:50 +08:00
exit_ok = true ;
2018-10-06 20:41:31 +08:00
# endif
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_ITERATE_BEGIN ) {
2017-09-02 22:19:06 +08:00
CHECK_SPACE ( 8 ) ; //space for this a regular iterate
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( counter , 1 ) ;
GET_VARIANT_PTR ( container , 2 ) ;
2016-06-01 09:28:27 +08:00
bool valid ;
2017-03-05 23:44:50 +08:00
if ( ! container - > iter_init ( * counter , valid ) ) {
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
if ( ! valid ) {
2019-10-05 21:33:30 +08:00
err_text = " Unable to iterate on object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " '. " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
int jumpto = _code_ptr [ ip + 3 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
2017-03-05 23:44:50 +08:00
ip = jumpto ;
2017-11-10 00:13:04 +08:00
} else {
GET_VARIANT_PTR ( iterator , 4 ) ;
2016-06-01 09:28:27 +08:00
2017-11-10 00:13:04 +08:00
* iterator = container - > iter_get ( * counter , valid ) ;
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2017-11-10 00:13:04 +08:00
if ( ! valid ) {
2019-10-05 21:33:30 +08:00
err_text = " Unable to obtain iterator object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " '. " ;
2017-11-10 00:13:04 +08:00
OPCODE_BREAK ;
}
2017-09-19 06:06:27 +08:00
# endif
2017-11-10 00:13:04 +08:00
ip + = 5 ; //skip regular iterate which is always next
}
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_ITERATE ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 4 ) ;
2017-03-05 23:44:50 +08:00
GET_VARIANT_PTR ( counter , 1 ) ;
GET_VARIANT_PTR ( container , 2 ) ;
2016-06-01 09:28:27 +08:00
bool valid ;
2017-03-05 23:44:50 +08:00
if ( ! container - > iter_next ( * counter , valid ) ) {
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
if ( ! valid ) {
2019-10-05 21:33:30 +08:00
err_text = " Unable to iterate on object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " ' (type changed since first iteration?). " ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2017-03-05 23:44:50 +08:00
int jumpto = _code_ptr [ ip + 3 ] ;
2017-09-19 06:06:27 +08:00
GD_ERR_BREAK ( jumpto < 0 | | jumpto > _code_size ) ;
2017-03-05 23:44:50 +08:00
ip = jumpto ;
2017-11-10 00:13:04 +08:00
} else {
GET_VARIANT_PTR ( iterator , 4 ) ;
2016-06-01 09:28:27 +08:00
2017-11-10 00:13:04 +08:00
* iterator = container - > iter_get ( * counter , valid ) ;
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2017-11-10 00:13:04 +08:00
if ( ! valid ) {
2019-10-05 21:33:30 +08:00
err_text = " Unable to obtain iterator object of type ' " + Variant : : get_type_name ( container - > get_type ( ) ) + " ' (but was obtained on first iteration?). " ;
2017-11-10 00:13:04 +08:00
OPCODE_BREAK ;
}
2017-09-19 06:06:27 +08:00
# endif
2017-11-10 00:13:04 +08:00
ip + = 5 ; //loop again
}
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_ASSERT ) {
2019-08-06 19:28:22 +08:00
CHECK_SPACE ( 3 ) ;
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
2018-10-06 20:41:31 +08:00
GET_VARIANT_PTR ( test , 1 ) ;
2017-09-19 02:02:47 +08:00
bool result = test - > booleanize ( ) ;
2016-06-01 09:28:27 +08:00
if ( ! result ) {
2020-05-27 07:38:44 +08:00
String message_str ;
if ( _code_ptr [ ip + 2 ] ! = 0 ) {
GET_VARIANT_PTR ( message , 2 ) ;
message_str = * message ;
}
2019-08-06 19:28:22 +08:00
if ( message_str . empty ( ) ) {
err_text = " Assertion failed. " ;
} else {
err_text = " Assertion failed: " + message_str ;
}
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2016-06-01 09:28:27 +08:00
}
# endif
2019-08-06 19:28:22 +08:00
ip + = 3 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_BREAKPOINT ) {
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
2020-02-27 10:30:20 +08:00
if ( EngineDebugger : : is_active ( ) ) {
2017-03-05 23:44:50 +08:00
GDScriptLanguage : : get_singleton ( ) - > debug_break ( " Breakpoint Statement " , true ) ;
2016-06-01 09:28:27 +08:00
}
# endif
2017-03-05 23:44:50 +08:00
ip + = 1 ;
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_LINE ) {
2016-06-01 09:28:27 +08:00
CHECK_SPACE ( 2 ) ;
2017-03-05 23:44:50 +08:00
line = _code_ptr [ ip + 1 ] ;
ip + = 2 ;
2016-06-01 09:28:27 +08:00
2020-02-27 10:30:20 +08:00
if ( EngineDebugger : : is_active ( ) ) {
2016-06-01 09:28:27 +08:00
// line
2017-03-05 23:44:50 +08:00
bool do_break = false ;
2016-06-01 09:28:27 +08:00
2020-02-27 10:30:20 +08:00
if ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) > 0 ) {
2020-05-14 22:41:43 +08:00
if ( EngineDebugger : : get_script_debugger ( ) - > get_depth ( ) < = 0 ) {
2020-02-27 10:30:20 +08:00
EngineDebugger : : get_script_debugger ( ) - > set_lines_left ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) - 1 ) ;
2020-05-14 22:41:43 +08:00
}
if ( EngineDebugger : : get_script_debugger ( ) - > get_lines_left ( ) < = 0 ) {
2017-03-05 23:44:50 +08:00
do_break = true ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
}
2020-05-14 22:41:43 +08:00
if ( EngineDebugger : : get_script_debugger ( ) - > is_breakpoint ( line , source ) ) {
2017-03-05 23:44:50 +08:00
do_break = true ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
if ( do_break ) {
2017-03-05 23:44:50 +08:00
GDScriptLanguage : : get_singleton ( ) - > debug_break ( " Breakpoint " , true ) ;
2016-06-01 09:28:27 +08:00
}
2020-02-27 10:30:20 +08:00
EngineDebugger : : get_singleton ( ) - > line_poll ( ) ;
2016-06-01 09:28:27 +08:00
}
2017-01-15 23:38:54 +08:00
}
2017-11-10 00:13:04 +08:00
DISPATCH_OPCODE ;
2017-09-24 02:06:58 +08:00
OPCODE ( OPCODE_END ) {
2018-10-06 20:41:31 +08:00
# ifdef DEBUG_ENABLED
2017-03-05 23:44:50 +08:00
exit_ok = true ;
2018-10-06 20:41:31 +08:00
# endif
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2017-01-15 23:38:54 +08:00
}
2017-12-17 22:29:39 +08:00
2020-01-22 04:32:27 +08:00
#if 0 // Enable for debugging.
2016-06-01 09:28:27 +08:00
default : {
2017-03-05 23:44:50 +08:00
err_text = " Illegal opcode " + itos ( _code_ptr [ ip ] ) + " at address " + itos ( ip ) ;
2017-09-24 02:06:58 +08:00
OPCODE_BREAK ;
2017-01-15 23:38:54 +08:00
}
2017-09-24 02:06:58 +08:00
# endif
2016-06-01 09:28:27 +08:00
}
2017-09-24 02:06:58 +08:00
OPCODES_END
2017-09-19 06:06:27 +08:00
# ifdef DEBUG_ENABLED
2020-05-14 22:41:43 +08:00
if ( exit_ok ) {
2017-09-24 02:06:58 +08:00
OPCODE_OUT ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
//error
// function, file, line, error, explanation
String err_file ;
2020-05-14 22:41:43 +08:00
if ( p_instance & & ObjectDB : : get_instance ( p_instance - > owner_id ) ! = nullptr & & p_instance - > script - > is_valid ( ) & & p_instance - > script - > path ! = " " ) {
2017-03-05 23:44:50 +08:00
err_file = p_instance - > script - > path ;
2020-05-14 22:41:43 +08:00
} else if ( script ) {
2018-10-18 02:36:47 +08:00
err_file = script - > path ;
2020-05-14 22:41:43 +08:00
}
if ( err_file = = " " ) {
2017-03-05 23:44:50 +08:00
err_file = " <built-in> " ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
String err_func = name ;
2020-05-14 22:41:43 +08:00
if ( p_instance & & ObjectDB : : get_instance ( p_instance - > owner_id ) ! = nullptr & & p_instance - > script - > is_valid ( ) & & p_instance - > script - > name ! = " " ) {
2017-03-05 23:44:50 +08:00
err_func = p_instance - > script - > name + " . " + err_func ;
2020-05-14 22:41:43 +08:00
}
2017-03-05 23:44:50 +08:00
int err_line = line ;
if ( err_text = = " " ) {
err_text = " Internal Script Error! - opcode # " + itos ( last_opcode ) + " (report please). " ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
if ( ! GDScriptLanguage : : get_singleton ( ) - > debug_break ( err_text , false ) ) {
2016-06-01 09:28:27 +08:00
// debugger break did not happen
2017-03-05 23:44:50 +08:00
_err_print_error ( err_func . utf8 ( ) . get_data ( ) , err_file . utf8 ( ) . get_data ( ) , err_line , err_text . utf8 ( ) . get_data ( ) , ERR_HANDLER_SCRIPT ) ;
2016-06-01 09:28:27 +08:00
}
2017-09-19 06:06:27 +08:00
# endif
2017-09-24 02:06:58 +08:00
OPCODE_OUT ;
2016-06-01 09:28:27 +08:00
}
2017-09-24 02:06:58 +08:00
OPCODES_OUT
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
if ( GDScriptLanguage : : get_singleton ( ) - > profiling ) {
uint64_t time_taken = OS : : get_singleton ( ) - > get_ticks_usec ( ) - function_start_time ;
2017-03-05 23:44:50 +08:00
profile . total_time + = time_taken ;
profile . self_time + = time_taken - function_call_time ;
profile . frame_total_time + = time_taken ;
profile . frame_self_time + = time_taken - function_call_time ;
GDScriptLanguage : : get_singleton ( ) - > script_frame_time + = time_taken - function_call_time ;
2016-06-01 09:28:27 +08:00
}
2020-05-02 06:14:56 +08:00
// Check if this is the last time the function is resuming from await
// Will be true if never awaited as well
2019-05-11 03:38:48 +08:00
// When it's the last resume it will postpone the exit from stack,
// so the debugger knows which function triggered the resume of the next function (if any)
2020-05-02 06:14:56 +08:00
if ( ! p_state | | awaited ) {
2020-05-14 22:41:43 +08:00
if ( EngineDebugger : : is_active ( ) ) {
2019-05-11 03:38:48 +08:00
GDScriptLanguage : : get_singleton ( ) - > exit_function ( ) ;
2020-05-14 22:41:43 +08:00
}
2018-05-02 06:40:30 +08:00
# endif
2016-06-01 09:28:27 +08:00
2019-05-11 03:38:48 +08:00
if ( _stack_size ) {
//free stack
2020-05-14 22:41:43 +08:00
for ( int i = 0 ; i < _stack_size ; i + + ) {
2019-05-11 03:38:48 +08:00
stack [ i ] . ~ Variant ( ) ;
2020-05-14 22:41:43 +08:00
}
2019-05-11 03:38:48 +08:00
}
# ifdef DEBUG_ENABLED
2016-06-01 09:28:27 +08:00
}
2019-05-11 03:38:48 +08:00
# endif
2016-06-01 09:28:27 +08:00
return retvalue ;
}
2017-11-17 01:38:18 +08:00
const int * GDScriptFunction : : get_code ( ) const {
2016-06-01 09:28:27 +08:00
return _code_ptr ;
}
2020-05-14 20:29:06 +08:00
2017-11-17 01:38:18 +08:00
int GDScriptFunction : : get_code_size ( ) const {
2016-06-01 09:28:27 +08:00
return _code_size ;
}
2017-11-17 01:38:18 +08:00
Variant GDScriptFunction : : get_constant ( int p_idx ) const {
2017-03-05 23:44:50 +08:00
ERR_FAIL_INDEX_V ( p_idx , constants . size ( ) , " <errconst> " ) ;
2016-06-01 09:28:27 +08:00
return constants [ p_idx ] ;
}
2017-11-17 01:38:18 +08:00
StringName GDScriptFunction : : get_global_name ( int p_idx ) const {
2017-03-05 23:44:50 +08:00
ERR_FAIL_INDEX_V ( p_idx , global_names . size ( ) , " <errgname> " ) ;
2016-06-01 09:28:27 +08:00
return global_names [ p_idx ] ;
}
2017-11-17 01:38:18 +08:00
int GDScriptFunction : : get_default_argument_count ( ) const {
2018-07-25 22:41:27 +08:00
return _default_arg_count ;
2016-06-01 09:28:27 +08:00
}
2020-05-14 20:29:06 +08:00
2017-11-17 01:38:18 +08:00
int GDScriptFunction : : get_default_argument_addr ( int p_idx ) const {
2017-08-13 00:52:50 +08:00
ERR_FAIL_INDEX_V ( p_idx , default_arguments . size ( ) , - 1 ) ;
return default_arguments [ p_idx ] ;
2016-06-01 09:28:27 +08:00
}
2018-05-30 10:16:54 +08:00
GDScriptDataType GDScriptFunction : : get_return_type ( ) const {
return return_type ;
}
GDScriptDataType GDScriptFunction : : get_argument_type ( int p_idx ) const {
ERR_FAIL_INDEX_V ( p_idx , argument_types . size ( ) , GDScriptDataType ( ) ) ;
return argument_types [ p_idx ] ;
}
2017-11-17 01:38:18 +08:00
StringName GDScriptFunction : : get_name ( ) const {
2016-06-01 09:28:27 +08:00
return name ;
}
2017-11-17 01:38:18 +08:00
int GDScriptFunction : : get_max_stack_size ( ) const {
2016-06-01 09:28:27 +08:00
return _stack_size ;
}
struct _GDFKC {
int order ;
List < int > pos ;
} ;
struct _GDFKCS {
int order ;
StringName id ;
int pos ;
bool operator < ( const _GDFKCS & p_r ) const {
2017-03-05 23:44:50 +08:00
return order < p_r . order ;
2016-06-01 09:28:27 +08:00
}
} ;
2020-03-17 14:33:00 +08:00
void GDScriptFunction : : debug_get_stack_member_state ( int p_line , List < Pair < StringName , int > > * r_stackvars ) const {
2017-03-05 23:44:50 +08:00
int oc = 0 ;
Map < StringName , _GDFKC > sdmap ;
for ( const List < StackDebug > : : Element * E = stack_debug . front ( ) ; E ; E = E - > next ( ) ) {
const StackDebug & sd = E - > get ( ) ;
2020-05-14 22:41:43 +08:00
if ( sd . line > p_line ) {
2016-06-01 09:28:27 +08:00
break ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
if ( sd . added ) {
if ( ! sdmap . has ( sd . identifier ) ) {
_GDFKC d ;
2017-03-05 23:44:50 +08:00
d . order = oc + + ;
2016-06-01 09:28:27 +08:00
d . pos . push_back ( sd . pos ) ;
2017-03-05 23:44:50 +08:00
sdmap [ sd . identifier ] = d ;
2016-06-01 09:28:27 +08:00
} else {
sdmap [ sd . identifier ] . pos . push_back ( sd . pos ) ;
}
} else {
ERR_CONTINUE ( ! sdmap . has ( sd . identifier ) ) ;
sdmap [ sd . identifier ] . pos . pop_back ( ) ;
2020-05-14 22:41:43 +08:00
if ( sdmap [ sd . identifier ] . pos . empty ( ) ) {
2016-06-01 09:28:27 +08:00
sdmap . erase ( sd . identifier ) ;
2020-05-14 22:41:43 +08:00
}
2016-06-01 09:28:27 +08:00
}
}
List < _GDFKCS > stackpositions ;
2017-03-05 23:44:50 +08:00
for ( Map < StringName , _GDFKC > : : Element * E = sdmap . front ( ) ; E ; E = E - > next ( ) ) {
2016-06-01 09:28:27 +08:00
_GDFKCS spp ;
2017-03-05 23:44:50 +08:00
spp . id = E - > key ( ) ;
spp . order = E - > get ( ) . order ;
spp . pos = E - > get ( ) . pos . back ( ) - > get ( ) ;
2016-06-01 09:28:27 +08:00
stackpositions . push_back ( spp ) ;
}
stackpositions . sort ( ) ;
2017-03-05 23:44:50 +08:00
for ( List < _GDFKCS > : : Element * E = stackpositions . front ( ) ; E ; E = E - > next ( ) ) {
Pair < StringName , int > p ;
p . first = E - > get ( ) . id ;
p . second = E - > get ( ) . pos ;
2016-06-01 09:28:27 +08:00
r_stackvars - > push_back ( p ) ;
}
}
2017-12-07 04:36:34 +08:00
GDScriptFunction : : GDScriptFunction ( ) :
function_list ( this ) {
2017-03-05 23:44:50 +08:00
_stack_size = 0 ;
_call_size = 0 ;
2018-05-13 13:07:56 +08:00
rpc_mode = MultiplayerAPI : : RPC_MODE_DISABLED ;
2017-03-05 23:44:50 +08:00
name = " <anonymous> " ;
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
2020-04-02 07:20:12 +08:00
_func_cname = nullptr ;
2016-06-01 09:28:27 +08:00
2020-02-26 18:28:13 +08:00
{
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > lock ) ;
2016-06-01 09:28:27 +08:00
2020-02-26 18:28:13 +08:00
GDScriptLanguage : : get_singleton ( ) - > function_list . add ( & function_list ) ;
2016-06-01 09:28:27 +08:00
}
2017-03-05 23:44:50 +08:00
profile . call_count = 0 ;
profile . self_time = 0 ;
profile . total_time = 0 ;
profile . frame_call_count = 0 ;
profile . frame_self_time = 0 ;
profile . frame_total_time = 0 ;
profile . last_frame_call_count = 0 ;
profile . last_frame_self_time = 0 ;
profile . last_frame_total_time = 0 ;
2016-06-01 09:28:27 +08:00
# endif
}
2017-11-17 01:38:18 +08:00
GDScriptFunction : : ~ GDScriptFunction ( ) {
2016-06-01 09:28:27 +08:00
# ifdef DEBUG_ENABLED
2020-02-26 18:28:13 +08:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > lock ) ;
GDScriptLanguage : : get_singleton ( ) - > function_list . remove ( & function_list ) ;
2016-06-01 09:28:27 +08:00
# endif
}
/////////////////////
2020-02-20 03:27:19 +08:00
Variant GDScriptFunctionState : : _signal_callback ( const Variant * * p_args , int p_argcount , Callable : : CallError & r_error ) {
2016-06-01 09:28:27 +08:00
Variant arg ;
2020-02-20 03:27:19 +08:00
r_error . error = Callable : : CallError : : CALL_OK ;
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
if ( p_argcount = = 0 ) {
2020-02-20 03:27:19 +08:00
r_error . error = Callable : : CallError : : CALL_ERROR_TOO_FEW_ARGUMENTS ;
2017-03-05 23:44:50 +08:00
r_error . argument = 1 ;
2016-06-01 09:28:27 +08:00
return Variant ( ) ;
2017-03-05 23:44:50 +08:00
} else if ( p_argcount = = 1 ) {
2016-06-01 09:28:27 +08:00
//noooneee
2017-03-05 23:44:50 +08:00
} else if ( p_argcount = = 2 ) {
arg = * p_args [ 0 ] ;
2016-06-01 09:28:27 +08:00
} else {
Array extra_args ;
2017-03-05 23:44:50 +08:00
for ( int i = 0 ; i < p_argcount - 1 ; i + + ) {
2016-06-01 09:28:27 +08:00
extra_args . push_back ( * p_args [ i ] ) ;
}
2017-03-05 23:44:50 +08:00
arg = extra_args ;
2016-06-01 09:28:27 +08:00
}
2017-11-17 01:38:18 +08:00
Ref < GDScriptFunctionState > self = * p_args [ p_argcount - 1 ] ;
2016-06-01 09:28:27 +08:00
if ( self . is_null ( ) ) {
2020-02-20 03:27:19 +08:00
r_error . error = Callable : : CallError : : CALL_ERROR_INVALID_ARGUMENT ;
2017-03-05 23:44:50 +08:00
r_error . argument = p_argcount - 1 ;
r_error . expected = Variant : : OBJECT ;
2016-06-01 09:28:27 +08:00
return Variant ( ) ;
}
2019-07-18 04:47:00 +08:00
return resume ( arg ) ;
2016-06-01 09:28:27 +08:00
}
2017-11-17 01:38:18 +08:00
bool GDScriptFunctionState : : is_valid ( bool p_extended_check ) const {
2020-05-14 22:41:43 +08:00
if ( function = = nullptr ) {
2017-05-17 20:47:17 +08:00
return false ;
2020-05-14 22:41:43 +08:00
}
2017-05-17 20:47:17 +08:00
if ( p_extended_check ) {
2020-05-05 18:53:05 +08:00
MutexLock lock ( GDScriptLanguage : : get_singleton ( ) - > lock ) ;
// Script gone?
if ( ! scripts_list . in_list ( ) ) {
2017-05-17 20:47:17 +08:00
return false ;
2020-04-29 19:38:00 +08:00
}
2020-05-05 18:53:05 +08:00
// Class instance gone? (if not static function)
if ( state . instance & & ! instances_list . in_list ( ) ) {
2020-04-29 19:38:00 +08:00
return false ;
}
2017-05-17 20:47:17 +08:00
}
2016-06-01 09:28:27 +08:00
2017-05-17 20:47:17 +08:00
return true ;
2016-06-01 09:28:27 +08:00
}
2017-11-17 01:38:18 +08:00
Variant GDScriptFunctionState : : resume ( const Variant & p_arg ) {
2017-03-05 23:44:50 +08:00
ERR_FAIL_COND_V ( ! function , Variant ( ) ) ;
2020-05-05 18:53:05 +08:00
{
MutexLock lock ( GDScriptLanguage : : singleton - > lock ) ;
if ( ! scripts_list . in_list ( ) ) {
2018-11-25 19:38:12 +08:00
# ifdef DEBUG_ENABLED
2020-05-02 06:14:56 +08:00
ERR_FAIL_V_MSG ( Variant ( ) , " Resumed function ' " + state . function_name + " ()' after await, but script is gone. At script: " + state . script_path + " : " + itos ( state . line ) ) ;
2020-04-29 19:38:00 +08:00
# else
2020-05-05 18:53:05 +08:00
return Variant ( ) ;
2020-04-29 19:38:00 +08:00
# endif
2020-05-05 18:53:05 +08:00
}
if ( state . instance & & ! instances_list . in_list ( ) ) {
2020-04-29 19:38:00 +08:00
# ifdef DEBUG_ENABLED
2020-05-02 06:14:56 +08:00
ERR_FAIL_V_MSG ( Variant ( ) , " Resumed function ' " + state . function_name + " ()' after await, but class instance is gone. At script: " + state . script_path + " : " + itos ( state . line ) ) ;
2018-11-25 19:38:12 +08:00
# else
2020-05-05 18:53:05 +08:00
return Variant ( ) ;
2016-06-30 08:06:16 +08:00
# endif
2020-05-05 18:53:05 +08:00
}
// Do these now to avoid locking again after the call
scripts_list . remove_from_list ( ) ;
instances_list . remove_from_list ( ) ;
2018-11-25 19:38:12 +08:00
}
2016-06-01 09:28:27 +08:00
2017-03-05 23:44:50 +08:00
state . result = p_arg ;
2020-02-20 03:27:19 +08:00
Callable : : CallError err ;
2020-04-02 07:20:12 +08:00
Variant ret = function - > call ( nullptr , nullptr , 0 , err , & state ) ;
2017-06-23 08:29:23 +08:00
bool completed = true ;
2017-11-17 01:38:18 +08:00
// If the return value is a GDScriptFunctionState reference,
2020-05-02 06:14:56 +08:00
// then the function did awaited again after resuming.
2017-06-23 08:29:23 +08:00
if ( ret . is_ref ( ) ) {
2017-11-17 01:38:18 +08:00
GDScriptFunctionState * gdfs = Object : : cast_to < GDScriptFunctionState > ( ret ) ;
2018-03-14 23:42:13 +08:00
if ( gdfs & & gdfs - > function = = function ) {
2017-06-23 08:29:23 +08:00
completed = false ;
2018-06-28 23:40:11 +08:00
gdfs - > first_state = first_state . is_valid ( ) ? first_state : Ref < GDScriptFunctionState > ( this ) ;
2018-03-14 23:42:13 +08:00
}
2017-06-23 08:29:23 +08:00
}
2020-04-02 07:20:12 +08:00
function = nullptr ; //cleaned up;
2017-03-05 23:44:50 +08:00
state . result = Variant ( ) ;
2017-06-23 08:29:23 +08:00
if ( completed ) {
2018-06-28 23:40:11 +08:00
if ( first_state . is_valid ( ) ) {
first_state - > emit_signal ( " completed " , ret ) ;
} else {
emit_signal ( " completed " , ret ) ;
2018-03-14 23:42:13 +08:00
}
2019-05-11 03:38:48 +08:00
# ifdef DEBUG_ENABLED
2020-05-14 22:41:43 +08:00
if ( EngineDebugger : : is_active ( ) ) {
2019-05-11 03:38:48 +08:00
GDScriptLanguage : : get_singleton ( ) - > exit_function ( ) ;
2020-05-14 22:41:43 +08:00
}
2019-05-11 03:38:48 +08:00
# endif
2017-06-23 08:29:23 +08:00
}
2016-06-01 09:28:27 +08:00
return ret ;
}
2020-05-05 18:53:05 +08:00
void GDScriptFunctionState : : _clear_stack ( ) {
if ( state . stack_size ) {
Variant * stack = ( Variant * ) state . stack . ptr ( ) ;
2020-05-14 22:41:43 +08:00
for ( int i = 0 ; i < state . stack_size ; i + + ) {
2020-05-05 18:53:05 +08:00
stack [ i ] . ~ Variant ( ) ;
2020-05-14 22:41:43 +08:00
}
2020-05-05 18:53:05 +08:00
state . stack_size = 0 ;
}
}
2017-11-17 01:38:18 +08:00
void GDScriptFunctionState : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " resume " , " arg " ) , & GDScriptFunctionState : : resume , DEFVAL ( Variant ( ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " is_valid " , " extended_check " ) , & GDScriptFunctionState : : is_valid , DEFVAL ( false ) ) ;
ClassDB : : bind_vararg_method ( METHOD_FLAGS_DEFAULT , " _signal_callback " , & GDScriptFunctionState : : _signal_callback , MethodInfo ( " _signal_callback " ) ) ;
2017-06-23 08:29:23 +08:00
2017-10-05 19:44:00 +08:00
ADD_SIGNAL ( MethodInfo ( " completed " , PropertyInfo ( Variant : : NIL , " result " , PROPERTY_HINT_NONE , " " , PROPERTY_USAGE_NIL_IS_VARIANT ) ) ) ;
2016-06-01 09:28:27 +08:00
}
2020-05-05 18:53:05 +08:00
GDScriptFunctionState : : GDScriptFunctionState ( ) :
scripts_list ( this ) ,
instances_list ( this ) {
2020-04-02 07:20:12 +08:00
function = nullptr ;
2016-06-01 09:28:27 +08:00
}
2017-11-17 01:38:18 +08:00
GDScriptFunctionState : : ~ GDScriptFunctionState ( ) {
2020-05-05 18:53:05 +08:00
_clear_stack ( ) ;
{
MutexLock lock ( GDScriptLanguage : : singleton - > lock ) ;
scripts_list . remove_from_list ( ) ;
instances_list . remove_from_list ( ) ;
2016-06-01 09:28:27 +08:00
}
}