1 /*************************************************************************/ 2 /* gdscript_function.h */ 3 /*************************************************************************/ 4 /* This file is part of: */ 5 /* GODOT ENGINE */ 6 /* https://godotengine.org */ 7 /*************************************************************************/ 8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ 9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ 10 /* */ 11 /* Permission is hereby granted, free of charge, to any person obtaining */ 12 /* a copy of this software and associated documentation files (the */ 13 /* "Software"), to deal in the Software without restriction, including */ 14 /* without limitation the rights to use, copy, modify, merge, publish, */ 15 /* distribute, sublicense, and/or sell copies of the Software, and to */ 16 /* permit persons to whom the Software is furnished to do so, subject to */ 17 /* the following conditions: */ 18 /* */ 19 /* The above copyright notice and this permission notice shall be */ 20 /* included in all copies or substantial portions of the Software. */ 21 /* */ 22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ 23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ 24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ 25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ 26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ 27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ 28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ 29 /*************************************************************************/ 30 31 #ifndef GDSCRIPT_FUNCTION_H 32 #define GDSCRIPT_FUNCTION_H 33 34 #include "core/os/thread.h" 35 #include "core/pair.h" 36 #include "core/reference.h" 37 #include "core/script_language.h" 38 #include "core/self_list.h" 39 #include "core/string_name.h" 40 #include "core/variant.h" 41 42 class GDScriptInstance; 43 class GDScript; 44 45 struct GDScriptDataType { 46 bool has_type; 47 enum { 48 UNINITIALIZED, 49 BUILTIN, 50 NATIVE, 51 SCRIPT, 52 GDSCRIPT, 53 } kind; 54 Variant::Type builtin_type; 55 StringName native_type; 56 Ref<Script> script_type; 57 58 bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const { 59 if (!has_type) return true; // Can't type check 60 61 switch (kind) { 62 case UNINITIALIZED: 63 break; 64 case BUILTIN: { 65 Variant::Type var_type = p_variant.get_type(); 66 bool valid = builtin_type == var_type; 67 if (!valid && p_allow_implicit_conversion) { 68 valid = Variant::can_convert_strict(var_type, builtin_type); 69 } 70 return valid; 71 } break; 72 case NATIVE: { 73 if (p_variant.get_type() == Variant::NIL) { 74 return true; 75 } 76 if (p_variant.get_type() != Variant::OBJECT) { 77 return false; 78 } 79 80 Object *obj = p_variant.operator Object *(); 81 if (!obj || !ObjectDB::instance_validate(obj)) { 82 return false; 83 } 84 85 if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) { 86 // Try with underscore prefix 87 StringName underscore_native_type = "_" + native_type; 88 if (!ClassDB::is_parent_class(obj->get_class_name(), underscore_native_type)) { 89 return false; 90 } 91 } 92 return true; 93 } break; 94 case SCRIPT: 95 case GDSCRIPT: { 96 if (p_variant.get_type() == Variant::NIL) { 97 return true; 98 } 99 if (p_variant.get_type() != Variant::OBJECT) { 100 return false; 101 } 102 103 Object *obj = p_variant.operator Object *(); 104 if (!obj || !ObjectDB::instance_validate(obj)) { 105 return false; 106 } 107 108 Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : NULL; 109 bool valid = false; 110 while (base.is_valid()) { 111 if (base == script_type) { 112 valid = true; 113 break; 114 } 115 base = base->get_base_script(); 116 } 117 return valid; 118 } break; 119 } 120 return false; 121 } 122 PropertyInfoGDScriptDataType123 operator PropertyInfo() const { 124 PropertyInfo info; 125 if (has_type) { 126 switch (kind) { 127 case UNINITIALIZED: 128 break; 129 case BUILTIN: { 130 info.type = builtin_type; 131 } break; 132 case NATIVE: { 133 info.type = Variant::OBJECT; 134 info.class_name = native_type; 135 } break; 136 case SCRIPT: 137 case GDSCRIPT: { 138 info.type = Variant::OBJECT; 139 info.class_name = script_type->get_instance_base_type(); 140 } break; 141 } 142 } else { 143 info.type = Variant::NIL; 144 info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; 145 } 146 return info; 147 } 148 GDScriptDataTypeGDScriptDataType149 GDScriptDataType() : 150 has_type(false), 151 kind(UNINITIALIZED), 152 builtin_type(Variant::NIL) {} 153 }; 154 155 class GDScriptFunction { 156 public: 157 enum Opcode { 158 OPCODE_OPERATOR, 159 OPCODE_EXTENDS_TEST, 160 OPCODE_IS_BUILTIN, 161 OPCODE_SET, 162 OPCODE_GET, 163 OPCODE_SET_NAMED, 164 OPCODE_GET_NAMED, 165 OPCODE_SET_MEMBER, 166 OPCODE_GET_MEMBER, 167 OPCODE_ASSIGN, 168 OPCODE_ASSIGN_TRUE, 169 OPCODE_ASSIGN_FALSE, 170 OPCODE_ASSIGN_TYPED_BUILTIN, 171 OPCODE_ASSIGN_TYPED_NATIVE, 172 OPCODE_ASSIGN_TYPED_SCRIPT, 173 OPCODE_CAST_TO_BUILTIN, 174 OPCODE_CAST_TO_NATIVE, 175 OPCODE_CAST_TO_SCRIPT, 176 OPCODE_CONSTRUCT, //only for basic types!! 177 OPCODE_CONSTRUCT_ARRAY, 178 OPCODE_CONSTRUCT_DICTIONARY, 179 OPCODE_CALL, 180 OPCODE_CALL_RETURN, 181 OPCODE_CALL_BUILT_IN, 182 OPCODE_CALL_SELF, 183 OPCODE_CALL_SELF_BASE, 184 OPCODE_YIELD, 185 OPCODE_YIELD_SIGNAL, 186 OPCODE_YIELD_RESUME, 187 OPCODE_JUMP, 188 OPCODE_JUMP_IF, 189 OPCODE_JUMP_IF_NOT, 190 OPCODE_JUMP_TO_DEF_ARGUMENT, 191 OPCODE_RETURN, 192 OPCODE_ITERATE_BEGIN, 193 OPCODE_ITERATE, 194 OPCODE_ASSERT, 195 OPCODE_BREAKPOINT, 196 OPCODE_LINE, 197 OPCODE_END 198 }; 199 200 enum Address { 201 ADDR_BITS = 24, 202 ADDR_MASK = ((1 << ADDR_BITS) - 1), 203 ADDR_TYPE_MASK = ~ADDR_MASK, 204 ADDR_TYPE_SELF = 0, 205 ADDR_TYPE_CLASS = 1, 206 ADDR_TYPE_MEMBER = 2, 207 ADDR_TYPE_CLASS_CONSTANT = 3, 208 ADDR_TYPE_LOCAL_CONSTANT = 4, 209 ADDR_TYPE_STACK = 5, 210 ADDR_TYPE_STACK_VARIABLE = 6, 211 ADDR_TYPE_GLOBAL = 7, 212 ADDR_TYPE_NAMED_GLOBAL = 8, 213 ADDR_TYPE_NIL = 9 214 }; 215 216 struct StackDebug { 217 218 int line; 219 int pos; 220 bool added; 221 StringName identifier; 222 }; 223 224 private: 225 friend class GDScriptCompiler; 226 227 StringName source; 228 229 mutable Variant nil; 230 mutable Variant *_constants_ptr; 231 int _constant_count; 232 const StringName *_global_names_ptr; 233 int _global_names_count; 234 #ifdef TOOLS_ENABLED 235 const StringName *_named_globals_ptr; 236 int _named_globals_count; 237 #endif 238 const int *_default_arg_ptr; 239 int _default_arg_count; 240 const int *_code_ptr; 241 int _code_size; 242 int _argument_count; 243 int _stack_size; 244 int _call_size; 245 int _initial_line; 246 bool _static; 247 MultiplayerAPI::RPCMode rpc_mode; 248 249 GDScript *_script; 250 251 StringName name; 252 Vector<Variant> constants; 253 Vector<StringName> global_names; 254 #ifdef TOOLS_ENABLED 255 Vector<StringName> named_globals; 256 #endif 257 Vector<int> default_arguments; 258 Vector<int> code; 259 Vector<GDScriptDataType> argument_types; 260 GDScriptDataType return_type; 261 262 #ifdef TOOLS_ENABLED 263 Vector<StringName> arg_names; 264 #endif 265 266 List<StackDebug> stack_debug; 267 268 _FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant *p_stack, String &r_error) const; 269 _FORCE_INLINE_ String _get_call_error(const Variant::CallError &p_err, const String &p_where, const Variant **argptrs) const; 270 271 friend class GDScriptLanguage; 272 273 SelfList<GDScriptFunction> function_list; 274 #ifdef DEBUG_ENABLED 275 CharString func_cname; 276 const char *_func_cname; 277 278 struct Profile { 279 StringName signature; 280 uint64_t call_count; 281 uint64_t self_time; 282 uint64_t total_time; 283 uint64_t frame_call_count; 284 uint64_t frame_self_time; 285 uint64_t frame_total_time; 286 uint64_t last_frame_call_count; 287 uint64_t last_frame_self_time; 288 uint64_t last_frame_total_time; 289 } profile; 290 291 #endif 292 293 public: 294 struct CallState { 295 296 GDScript *script; 297 GDScriptInstance *instance; 298 #ifdef DEBUG_ENABLED 299 StringName function_name; 300 String script_path; 301 #endif 302 Vector<uint8_t> stack; 303 int stack_size; 304 Variant self; 305 uint32_t alloca_size; 306 int ip; 307 int line; 308 int defarg; 309 Variant result; 310 }; 311 is_static()312 _FORCE_INLINE_ bool is_static() const { return _static; } 313 314 const int *get_code() const; //used for debug 315 int get_code_size() const; 316 Variant get_constant(int p_idx) const; 317 StringName get_global_name(int p_idx) const; 318 StringName get_name() const; 319 int get_max_stack_size() const; 320 int get_default_argument_count() const; 321 int get_default_argument_addr(int p_idx) const; 322 GDScriptDataType get_return_type() const; 323 GDScriptDataType get_argument_type(int p_idx) const; get_script()324 GDScript *get_script() const { return _script; } get_source()325 StringName get_source() const { return source; } 326 327 void debug_get_stack_member_state(int p_line, List<Pair<StringName, int> > *r_stackvars) const; 328 is_empty()329 _FORCE_INLINE_ bool is_empty() const { return _code_size == 0; } 330 get_argument_count()331 int get_argument_count() const { return _argument_count; } get_argument_name(int p_idx)332 StringName get_argument_name(int p_idx) const { 333 #ifdef TOOLS_ENABLED 334 ERR_FAIL_INDEX_V(p_idx, arg_names.size(), StringName()); 335 return arg_names[p_idx]; 336 #else 337 return StringName(); 338 #endif 339 } get_default_argument(int p_idx)340 Variant get_default_argument(int p_idx) const { 341 ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), Variant()); 342 return default_arguments[p_idx]; 343 } 344 345 Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state = NULL); 346 get_rpc_mode()347 _FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const { return rpc_mode; } 348 GDScriptFunction(); 349 ~GDScriptFunction(); 350 }; 351 352 class GDScriptFunctionState : public Reference { 353 354 GDCLASS(GDScriptFunctionState, Reference); 355 friend class GDScriptFunction; 356 GDScriptFunction *function; 357 GDScriptFunction::CallState state; 358 Variant _signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error); 359 Ref<GDScriptFunctionState> first_state; 360 361 SelfList<GDScriptFunctionState> scripts_list; 362 SelfList<GDScriptFunctionState> instances_list; 363 364 protected: 365 static void _bind_methods(); 366 367 public: 368 bool is_valid(bool p_extended_check = false) const; 369 Variant resume(const Variant &p_arg = Variant()); 370 371 void _clear_stack(); 372 373 GDScriptFunctionState(); 374 ~GDScriptFunctionState(); 375 }; 376 377 #endif // GDSCRIPT_FUNCTION_H 378