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