mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-03 23:21:15 +00:00 
			
		
		
		
	Avoid losing references to objects in the native-scripting boundary
This commit is contained in:
		
							parent
							
								
									1ed549e64b
								
							
						
					
					
						commit
						0bcc7bb5c7
					
				
					 3 changed files with 40 additions and 1 deletions
				
			
		| 
						 | 
					@ -40,6 +40,8 @@
 | 
				
			||||||
#include "core/object/callable_method_pointer.h"
 | 
					#include "core/object/callable_method_pointer.h"
 | 
				
			||||||
#include "core/templates/hash_set.h"
 | 
					#include "core/templates/hash_set.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <type_traits>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEFVAL(m_defval) (m_defval)
 | 
					#define DEFVAL(m_defval) (m_defval)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG_METHODS_ENABLED
 | 
					#ifdef DEBUG_METHODS_ENABLED
 | 
				
			||||||
| 
						 | 
					@ -241,6 +243,24 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static uint64_t get_api_hash(APIType p_api);
 | 
						static uint64_t get_api_hash(APIType p_api);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <typename>
 | 
				
			||||||
 | 
						struct member_function_traits;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <typename R, typename T, typename... Args>
 | 
				
			||||||
 | 
						struct member_function_traits<R (T::*)(Args...)> {
 | 
				
			||||||
 | 
							using return_type = R;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <typename R, typename T, typename... Args>
 | 
				
			||||||
 | 
						struct member_function_traits<R (T::*)(Args...) const> {
 | 
				
			||||||
 | 
							using return_type = R;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						template <typename R, typename... Args>
 | 
				
			||||||
 | 
						struct member_function_traits<R (*)(Args...)> {
 | 
				
			||||||
 | 
							using return_type = R;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	template <class N, class M, typename... VarArgs>
 | 
						template <class N, class M, typename... VarArgs>
 | 
				
			||||||
	static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args) {
 | 
						static MethodBind *bind_method(N p_method_name, M p_method, VarArgs... p_args) {
 | 
				
			||||||
		Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
 | 
							Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
 | 
				
			||||||
| 
						 | 
					@ -249,6 +269,9 @@ public:
 | 
				
			||||||
			argptrs[i] = &args[i];
 | 
								argptrs[i] = &args[i];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		MethodBind *bind = create_method_bind(p_method);
 | 
							MethodBind *bind = create_method_bind(p_method);
 | 
				
			||||||
 | 
							if constexpr (std::is_same<typename member_function_traits<M>::return_type, Object *>::value) {
 | 
				
			||||||
 | 
								bind->set_return_type_is_raw_object_ptr(true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
 | 
							return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -261,6 +284,9 @@ public:
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		MethodBind *bind = create_static_method_bind(p_method);
 | 
							MethodBind *bind = create_static_method_bind(p_method);
 | 
				
			||||||
		bind->set_instance_class(p_class);
 | 
							bind->set_instance_class(p_class);
 | 
				
			||||||
 | 
							if constexpr (std::is_same<typename member_function_traits<M>::return_type, Object *>::value) {
 | 
				
			||||||
 | 
								bind->set_return_type_is_raw_object_ptr(true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
 | 
							return bind_methodfi(METHOD_FLAGS_DEFAULT, bind, p_method_name, sizeof...(p_args) == 0 ? nullptr : (const Variant **)argptrs, sizeof...(p_args));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -273,6 +299,9 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		bind->set_name(p_name);
 | 
							bind->set_name(p_name);
 | 
				
			||||||
		bind->set_default_arguments(p_default_args);
 | 
							bind->set_default_arguments(p_default_args);
 | 
				
			||||||
 | 
							if constexpr (std::is_same<typename member_function_traits<M>::return_type, Object *>::value) {
 | 
				
			||||||
 | 
								bind->set_return_type_is_raw_object_ptr(true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		String instance_type = bind->get_instance_class();
 | 
							String instance_type = bind->get_instance_class();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -49,6 +49,7 @@ class MethodBind {
 | 
				
			||||||
	bool _static = false;
 | 
						bool _static = false;
 | 
				
			||||||
	bool _const = false;
 | 
						bool _const = false;
 | 
				
			||||||
	bool _returns = false;
 | 
						bool _returns = false;
 | 
				
			||||||
 | 
						bool _returns_raw_obj_ptr = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
protected:
 | 
					protected:
 | 
				
			||||||
	Variant::Type *argument_types = nullptr;
 | 
						Variant::Type *argument_types = nullptr;
 | 
				
			||||||
| 
						 | 
					@ -121,6 +122,9 @@ public:
 | 
				
			||||||
	_FORCE_INLINE_ bool has_return() const { return _returns; }
 | 
						_FORCE_INLINE_ bool has_return() const { return _returns; }
 | 
				
			||||||
	virtual bool is_vararg() const { return false; }
 | 
						virtual bool is_vararg() const { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_FORCE_INLINE_ bool is_return_type_raw_object_ptr() { return _returns_raw_obj_ptr; }
 | 
				
			||||||
 | 
						_FORCE_INLINE_ void set_return_type_is_raw_object_ptr(bool p_returns_raw_obj) { _returns_raw_obj_ptr = p_returns_raw_obj; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void set_default_arguments(const Vector<Variant> &p_defargs);
 | 
						void set_default_arguments(const Vector<Variant> &p_defargs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t get_hash() const;
 | 
						uint32_t get_hash() const;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1969,7 +1969,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
 | 
				
			||||||
				VariantInternal::initialize(ret, Variant::OBJECT);
 | 
									VariantInternal::initialize(ret, Variant::OBJECT);
 | 
				
			||||||
				Object **ret_opaque = VariantInternal::get_object(ret);
 | 
									Object **ret_opaque = VariantInternal::get_object(ret);
 | 
				
			||||||
				method->ptrcall(base_obj, argptrs, ret_opaque);
 | 
									method->ptrcall(base_obj, argptrs, ret_opaque);
 | 
				
			||||||
 | 
									if (method->is_return_type_raw_object_ptr()) {
 | 
				
			||||||
 | 
										// The Variant has to participate in the ref count since the method returns a raw Object *.
 | 
				
			||||||
 | 
										VariantInternal::object_assign(ret, *ret_opaque);
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										// The method, in case it returns something, returns an already encapsulated object.
 | 
				
			||||||
					VariantInternal::update_object_id(ret);
 | 
										VariantInternal::update_object_id(ret);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef DEBUG_ENABLED
 | 
					#ifdef DEBUG_ENABLED
 | 
				
			||||||
				if (GDScriptLanguage::get_singleton()->profiling) {
 | 
									if (GDScriptLanguage::get_singleton()->profiling) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue