Merge pull request #86569 from rune-scape/rune-fix-lambda-hotswap2
GDScript: Lambda hotswap fixes
This commit is contained in:
commit
bf1de980e5
6 changed files with 92 additions and 180 deletions
|
@ -1381,51 +1381,43 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GDScript::UpdatableFuncPtr GDScript::func_ptrs_to_update_main_thread;
|
GDScript::UpdatableFuncPtr::UpdatableFuncPtr(GDScriptFunction *p_function) {
|
||||||
thread_local GDScript::UpdatableFuncPtr *GDScript::func_ptrs_to_update_thread_local = nullptr;
|
if (p_function == nullptr) {
|
||||||
|
return;
|
||||||
GDScript::UpdatableFuncPtrElement GDScript::_add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr) {
|
|
||||||
UpdatableFuncPtrElement result = {};
|
|
||||||
|
|
||||||
{
|
|
||||||
MutexLock lock(func_ptrs_to_update_thread_local->mutex);
|
|
||||||
result.element = func_ptrs_to_update_thread_local->ptrs.push_back(p_func_ptr_ptr);
|
|
||||||
result.func_ptr = func_ptrs_to_update_thread_local;
|
|
||||||
|
|
||||||
if (likely(func_ptrs_to_update_thread_local->initialized)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
func_ptrs_to_update_thread_local->initialized = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ptr = p_function;
|
||||||
|
script = ptr->get_script();
|
||||||
|
ERR_FAIL_NULL(script);
|
||||||
|
|
||||||
|
MutexLock script_lock(script->func_ptrs_to_update_mutex);
|
||||||
|
list_element = script->func_ptrs_to_update.push_back(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
GDScript::UpdatableFuncPtr::~UpdatableFuncPtr() {
|
||||||
|
ERR_FAIL_NULL(script);
|
||||||
|
|
||||||
|
if (list_element) {
|
||||||
|
MutexLock script_lock(script->func_ptrs_to_update_mutex);
|
||||||
|
list_element->erase();
|
||||||
|
list_element = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GDScript::_recurse_replace_function_ptrs(const HashMap<GDScriptFunction *, GDScriptFunction *> &p_replacements) const {
|
||||||
MutexLock lock(func_ptrs_to_update_mutex);
|
MutexLock lock(func_ptrs_to_update_mutex);
|
||||||
func_ptrs_to_update.push_back(func_ptrs_to_update_thread_local);
|
for (UpdatableFuncPtr *updatable : func_ptrs_to_update) {
|
||||||
func_ptrs_to_update_thread_local->rc++;
|
HashMap<GDScriptFunction *, GDScriptFunction *>::ConstIterator replacement = p_replacements.find(updatable->ptr);
|
||||||
|
if (replacement) {
|
||||||
|
updatable->ptr = replacement->value;
|
||||||
|
} else {
|
||||||
|
// Probably a lambda from another reload, ignore.
|
||||||
|
updatable->ptr = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
for (HashMap<StringName, Ref<GDScript>>::ConstIterator subscript = subclasses.begin(); subscript; ++subscript) {
|
||||||
}
|
subscript->value->_recurse_replace_function_ptrs(p_replacements);
|
||||||
|
|
||||||
void GDScript::_remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element) {
|
|
||||||
ERR_FAIL_NULL(p_func_ptr_element.element);
|
|
||||||
ERR_FAIL_NULL(p_func_ptr_element.func_ptr);
|
|
||||||
MutexLock lock(p_func_ptr_element.func_ptr->mutex);
|
|
||||||
p_func_ptr_element.element->erase();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDScript::_fixup_thread_function_bookkeeping() {
|
|
||||||
// Transfer the ownership of these update items to the main thread,
|
|
||||||
// because the current one is dying, leaving theirs orphan, dangling.
|
|
||||||
|
|
||||||
DEV_ASSERT(!Thread::is_main_thread());
|
|
||||||
|
|
||||||
MutexLock lock(func_ptrs_to_update_main_thread.mutex);
|
|
||||||
MutexLock lock2(func_ptrs_to_update_thread_local->mutex);
|
|
||||||
|
|
||||||
while (!func_ptrs_to_update_thread_local->ptrs.is_empty()) {
|
|
||||||
List<GDScriptFunction **>::Element *E = func_ptrs_to_update_thread_local->ptrs.front();
|
|
||||||
E->transfer_to_back(&func_ptrs_to_update_main_thread.ptrs);
|
|
||||||
func_ptrs_to_update_thread_local->transferred = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1447,30 +1439,9 @@ void GDScript::clear(ClearData *p_clear_data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
MutexLock outer_lock(func_ptrs_to_update_mutex);
|
MutexLock lock(func_ptrs_to_update_mutex);
|
||||||
for (UpdatableFuncPtr *updatable : func_ptrs_to_update) {
|
for (UpdatableFuncPtr *updatable : func_ptrs_to_update) {
|
||||||
bool destroy = false;
|
updatable->ptr = nullptr;
|
||||||
{
|
|
||||||
MutexLock inner_lock(updatable->mutex);
|
|
||||||
if (updatable->transferred) {
|
|
||||||
func_ptrs_to_update_main_thread.mutex.lock();
|
|
||||||
}
|
|
||||||
for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) {
|
|
||||||
*func_ptr_ptr = nullptr;
|
|
||||||
}
|
|
||||||
DEV_ASSERT(updatable->rc != 0);
|
|
||||||
updatable->rc--;
|
|
||||||
if (updatable->rc == 0) {
|
|
||||||
destroy = true;
|
|
||||||
}
|
|
||||||
if (updatable->transferred) {
|
|
||||||
func_ptrs_to_update_main_thread.mutex.unlock();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (destroy) {
|
|
||||||
DEV_ASSERT(updatable != &func_ptrs_to_update_main_thread);
|
|
||||||
memdelete(updatable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1543,6 +1514,13 @@ GDScript::~GDScript() {
|
||||||
}
|
}
|
||||||
destructing = true;
|
destructing = true;
|
||||||
|
|
||||||
|
if (is_print_verbose_enabled()) {
|
||||||
|
MutexLock lock(func_ptrs_to_update_mutex);
|
||||||
|
if (!func_ptrs_to_update.is_empty()) {
|
||||||
|
print_line(vformat("GDScript: %d orphaned lambdas becoming invalid at destruction of script '%s'.", func_ptrs_to_update.size(), fully_qualified_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -2091,33 +2069,6 @@ void GDScriptLanguage::remove_named_global_constant(const StringName &p_name) {
|
||||||
named_globals.erase(p_name);
|
named_globals.erase(p_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptLanguage::thread_enter() {
|
|
||||||
GDScript::func_ptrs_to_update_thread_local = memnew(GDScript::UpdatableFuncPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDScriptLanguage::thread_exit() {
|
|
||||||
// This thread may have been created before GDScript was up
|
|
||||||
// (which also means it can't have run any GDScript code at all).
|
|
||||||
if (!GDScript::func_ptrs_to_update_thread_local) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GDScript::_fixup_thread_function_bookkeeping();
|
|
||||||
|
|
||||||
bool destroy = false;
|
|
||||||
{
|
|
||||||
MutexLock lock(GDScript::func_ptrs_to_update_thread_local->mutex);
|
|
||||||
DEV_ASSERT(GDScript::func_ptrs_to_update_thread_local->rc != 0);
|
|
||||||
GDScript::func_ptrs_to_update_thread_local->rc--;
|
|
||||||
if (GDScript::func_ptrs_to_update_thread_local->rc == 0) {
|
|
||||||
destroy = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (destroy) {
|
|
||||||
memdelete(GDScript::func_ptrs_to_update_thread_local);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GDScriptLanguage::init() {
|
void GDScriptLanguage::init() {
|
||||||
//populate global constants
|
//populate global constants
|
||||||
int gcc = CoreConstants::get_global_constant_count();
|
int gcc = CoreConstants::get_global_constant_count();
|
||||||
|
@ -2150,8 +2101,6 @@ void GDScriptLanguage::init() {
|
||||||
_add_global(E.name, E.ptr);
|
_add_global(E.name, E.ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
GDScript::func_ptrs_to_update_thread_local = &GDScript::func_ptrs_to_update_main_thread;
|
|
||||||
|
|
||||||
#ifdef TESTS_ENABLED
|
#ifdef TESTS_ENABLED
|
||||||
GDScriptTests::GDScriptTestRunner::handle_cmdline();
|
GDScriptTests::GDScriptTestRunner::handle_cmdline();
|
||||||
#endif
|
#endif
|
||||||
|
@ -2201,8 +2150,6 @@ void GDScriptLanguage::finish() {
|
||||||
}
|
}
|
||||||
script_list.clear();
|
script_list.clear();
|
||||||
function_list.clear();
|
function_list.clear();
|
||||||
|
|
||||||
DEV_ASSERT(GDScript::func_ptrs_to_update_main_thread.rc == 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptLanguage::profiling_start() {
|
void GDScriptLanguage::profiling_start() {
|
||||||
|
|
|
@ -117,29 +117,28 @@ class GDScript : public Script {
|
||||||
|
|
||||||
HashMap<GDScriptFunction *, LambdaInfo> lambda_info;
|
HashMap<GDScriptFunction *, LambdaInfo> lambda_info;
|
||||||
|
|
||||||
|
public:
|
||||||
|
class UpdatableFuncPtr {
|
||||||
|
friend class GDScript;
|
||||||
|
|
||||||
|
GDScriptFunction *ptr = nullptr;
|
||||||
|
GDScript *script = nullptr;
|
||||||
|
List<UpdatableFuncPtr *>::Element *list_element = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GDScriptFunction *operator->() const { return ptr; }
|
||||||
|
operator GDScriptFunction *() const { return ptr; }
|
||||||
|
|
||||||
|
UpdatableFuncPtr(GDScriptFunction *p_function);
|
||||||
|
~UpdatableFuncPtr();
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
// List is used here because a ptr to elements are stored, so the memory locations need to be stable
|
// List is used here because a ptr to elements are stored, so the memory locations need to be stable
|
||||||
struct UpdatableFuncPtr {
|
|
||||||
List<GDScriptFunction **> ptrs;
|
|
||||||
Mutex mutex;
|
|
||||||
bool initialized : 1;
|
|
||||||
bool transferred : 1;
|
|
||||||
uint32_t rc = 1;
|
|
||||||
UpdatableFuncPtr() :
|
|
||||||
initialized(false), transferred(false) {}
|
|
||||||
};
|
|
||||||
struct UpdatableFuncPtrElement {
|
|
||||||
List<GDScriptFunction **>::Element *element = nullptr;
|
|
||||||
UpdatableFuncPtr *func_ptr = nullptr;
|
|
||||||
};
|
|
||||||
static UpdatableFuncPtr func_ptrs_to_update_main_thread;
|
|
||||||
static thread_local UpdatableFuncPtr *func_ptrs_to_update_thread_local;
|
|
||||||
List<UpdatableFuncPtr *> func_ptrs_to_update;
|
List<UpdatableFuncPtr *> func_ptrs_to_update;
|
||||||
Mutex func_ptrs_to_update_mutex;
|
Mutex func_ptrs_to_update_mutex;
|
||||||
|
|
||||||
UpdatableFuncPtrElement _add_func_ptr_to_update(GDScriptFunction **p_func_ptr_ptr);
|
void _recurse_replace_function_ptrs(const HashMap<GDScriptFunction *, GDScriptFunction *> &p_replacements) const;
|
||||||
static void _remove_func_ptr_to_update(const UpdatableFuncPtrElement &p_func_ptr_element);
|
|
||||||
|
|
||||||
static void _fixup_thread_function_bookkeeping();
|
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef TOOLS_ENABLED
|
||||||
// For static data storage during hot-reloading.
|
// For static data storage during hot-reloading.
|
||||||
|
@ -562,11 +561,6 @@ public:
|
||||||
virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override;
|
virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override;
|
||||||
virtual void remove_named_global_constant(const StringName &p_name) override;
|
virtual void remove_named_global_constant(const StringName &p_name) override;
|
||||||
|
|
||||||
/* MULTITHREAD FUNCTIONS */
|
|
||||||
|
|
||||||
virtual void thread_enter() override;
|
|
||||||
virtual void thread_exit() override;
|
|
||||||
|
|
||||||
/* DEBUGGER FUNCTIONS */
|
/* DEBUGGER FUNCTIONS */
|
||||||
|
|
||||||
virtual String debug_get_error() const override;
|
virtual String debug_get_error() const override;
|
||||||
|
|
|
@ -1375,7 +1375,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
||||||
return GDScriptCodeGenerator::Address();
|
return GDScriptCodeGenerator::Address();
|
||||||
}
|
}
|
||||||
|
|
||||||
main_script->lambda_info.insert(function, { lambda->captures.size(), lambda->use_self });
|
codegen.script->lambda_info.insert(function, { lambda->captures.size(), lambda->use_self });
|
||||||
gen->write_lambda(result, function, captures, lambda->use_self);
|
gen->write_lambda(result, function, captures, lambda->use_self);
|
||||||
|
|
||||||
for (int i = 0; i < captures.size(); i++) {
|
for (int i = 0; i < captures.size(); i++) {
|
||||||
|
@ -3050,7 +3050,7 @@ GDScriptCompiler::FunctionLambdaInfo GDScriptCompiler::_get_function_replacement
|
||||||
FunctionLambdaInfo info;
|
FunctionLambdaInfo info;
|
||||||
info.function = p_func;
|
info.function = p_func;
|
||||||
info.parent = p_parent_func;
|
info.parent = p_parent_func;
|
||||||
info.script = p_parent_func;
|
info.script = p_func->get_script();
|
||||||
info.name = p_func->get_name();
|
info.name = p_func->get_name();
|
||||||
info.line = p_func->_initial_line;
|
info.line = p_func->_initial_line;
|
||||||
info.index = p_index;
|
info.index = p_index;
|
||||||
|
@ -3061,10 +3061,14 @@ GDScriptCompiler::FunctionLambdaInfo GDScriptCompiler::_get_function_replacement
|
||||||
info.default_arg_count = p_func->_default_arg_count;
|
info.default_arg_count = p_func->_default_arg_count;
|
||||||
info.sublambdas = _get_function_lambda_replacement_info(p_func, p_depth, p_parent_func);
|
info.sublambdas = _get_function_lambda_replacement_info(p_func, p_depth, p_parent_func);
|
||||||
|
|
||||||
GDScript::LambdaInfo *extra_info = main_script->lambda_info.getptr(p_func);
|
ERR_FAIL_NULL_V(info.script, info);
|
||||||
|
GDScript::LambdaInfo *extra_info = info.script->lambda_info.getptr(p_func);
|
||||||
if (extra_info != nullptr) {
|
if (extra_info != nullptr) {
|
||||||
info.capture_count = extra_info->capture_count;
|
info.capture_count = extra_info->capture_count;
|
||||||
info.use_self = extra_info->use_self;
|
info.use_self = extra_info->use_self;
|
||||||
|
} else {
|
||||||
|
info.capture_count = 0;
|
||||||
|
info.use_self = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return info;
|
return info;
|
||||||
|
@ -3199,22 +3203,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
|
||||||
|
|
||||||
HashMap<GDScriptFunction *, GDScriptFunction *> func_ptr_replacements;
|
HashMap<GDScriptFunction *, GDScriptFunction *> func_ptr_replacements;
|
||||||
_get_function_ptr_replacements(func_ptr_replacements, old_lambda_info, &new_lambda_info);
|
_get_function_ptr_replacements(func_ptr_replacements, old_lambda_info, &new_lambda_info);
|
||||||
|
main_script->_recurse_replace_function_ptrs(func_ptr_replacements);
|
||||||
{
|
|
||||||
MutexLock outer_lock(main_script->func_ptrs_to_update_mutex);
|
|
||||||
for (GDScript::UpdatableFuncPtr *updatable : main_script->func_ptrs_to_update) {
|
|
||||||
MutexLock inner_lock(updatable->mutex);
|
|
||||||
for (GDScriptFunction **func_ptr_ptr : updatable->ptrs) {
|
|
||||||
GDScriptFunction **replacement = func_ptr_replacements.getptr(*func_ptr_ptr);
|
|
||||||
if (replacement != nullptr) {
|
|
||||||
*func_ptr_ptr = *replacement;
|
|
||||||
} else {
|
|
||||||
// Probably a lambda from another reload, ignore.
|
|
||||||
*func_ptr_ptr = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (has_static_data && !root->annotated_static_unload) {
|
if (has_static_data && !root->annotated_static_unload) {
|
||||||
GDScriptCache::add_static_script(p_script);
|
GDScriptCache::add_static_script(p_script);
|
||||||
|
|
|
@ -45,19 +45,19 @@ class GDScriptCompiler {
|
||||||
GDScript *main_script = nullptr;
|
GDScript *main_script = nullptr;
|
||||||
|
|
||||||
struct FunctionLambdaInfo {
|
struct FunctionLambdaInfo {
|
||||||
GDScriptFunction *function;
|
GDScriptFunction *function = nullptr;
|
||||||
GDScriptFunction *parent;
|
GDScriptFunction *parent = nullptr;
|
||||||
Ref<GDScript> script;
|
GDScript *script = nullptr;
|
||||||
StringName name;
|
StringName name;
|
||||||
int line;
|
int line = 0;
|
||||||
int index;
|
int index = 0;
|
||||||
int depth;
|
int depth = 0;
|
||||||
//uint64_t code_hash;
|
//uint64_t code_hash;
|
||||||
//int code_size;
|
//int code_size;
|
||||||
int capture_count;
|
int capture_count = 0;
|
||||||
int use_self;
|
bool use_self = false;
|
||||||
int arg_count;
|
int arg_count = 0;
|
||||||
int default_arg_count;
|
int default_arg_count = 0;
|
||||||
//Vector<GDScriptDataType> argument_types;
|
//Vector<GDScriptDataType> argument_types;
|
||||||
//GDScriptDataType return_type;
|
//GDScriptDataType return_type;
|
||||||
Vector<FunctionLambdaInfo> sublambdas;
|
Vector<FunctionLambdaInfo> sublambdas;
|
||||||
|
|
|
@ -139,20 +139,14 @@ void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, V
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
|
GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures) :
|
||||||
|
function(p_function) {
|
||||||
ERR_FAIL_NULL(p_script.ptr());
|
ERR_FAIL_NULL(p_script.ptr());
|
||||||
ERR_FAIL_NULL(p_function);
|
ERR_FAIL_NULL(p_function);
|
||||||
script = p_script;
|
script = p_script;
|
||||||
function = p_function;
|
|
||||||
captures = p_captures;
|
captures = p_captures;
|
||||||
|
|
||||||
h = (uint32_t)hash_murmur3_one_64((uint64_t)this);
|
h = (uint32_t)hash_murmur3_one_64((uint64_t)this);
|
||||||
|
|
||||||
updatable_func_ptr_element = p_script->_add_func_ptr_to_update(&function);
|
|
||||||
}
|
|
||||||
|
|
||||||
GDScriptLambdaCallable::~GDScriptLambdaCallable() {
|
|
||||||
GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GDScriptLambdaSelfCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
|
bool GDScriptLambdaSelfCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
|
||||||
|
@ -264,37 +258,23 @@ void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcoun
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
|
GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) :
|
||||||
|
function(p_function) {
|
||||||
ERR_FAIL_NULL(p_self.ptr());
|
ERR_FAIL_NULL(p_self.ptr());
|
||||||
ERR_FAIL_NULL(p_function);
|
ERR_FAIL_NULL(p_function);
|
||||||
reference = p_self;
|
reference = p_self;
|
||||||
object = p_self.ptr();
|
object = p_self.ptr();
|
||||||
function = p_function;
|
|
||||||
captures = p_captures;
|
captures = p_captures;
|
||||||
|
|
||||||
h = (uint32_t)hash_murmur3_one_64((uint64_t)this);
|
h = (uint32_t)hash_murmur3_one_64((uint64_t)this);
|
||||||
|
|
||||||
GDScript *gds = p_function->get_script();
|
|
||||||
if (gds != nullptr) {
|
|
||||||
updatable_func_ptr_element = gds->_add_func_ptr_to_update(&function);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
|
GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) :
|
||||||
|
function(p_function) {
|
||||||
ERR_FAIL_NULL(p_self);
|
ERR_FAIL_NULL(p_self);
|
||||||
ERR_FAIL_NULL(p_function);
|
ERR_FAIL_NULL(p_function);
|
||||||
object = p_self;
|
object = p_self;
|
||||||
function = p_function;
|
|
||||||
captures = p_captures;
|
captures = p_captures;
|
||||||
|
|
||||||
h = (uint32_t)hash_murmur3_one_64((uint64_t)this);
|
h = (uint32_t)hash_murmur3_one_64((uint64_t)this);
|
||||||
|
|
||||||
GDScript *gds = p_function->get_script();
|
|
||||||
if (gds != nullptr) {
|
|
||||||
updatable_func_ptr_element = gds->_add_func_ptr_to_update(&function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GDScriptLambdaSelfCallable::~GDScriptLambdaSelfCallable() {
|
|
||||||
GDScript::_remove_func_ptr_to_update(updatable_func_ptr_element);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,9 @@ class GDScriptFunction;
|
||||||
class GDScriptInstance;
|
class GDScriptInstance;
|
||||||
|
|
||||||
class GDScriptLambdaCallable : public CallableCustom {
|
class GDScriptLambdaCallable : public CallableCustom {
|
||||||
GDScriptFunction *function = nullptr;
|
GDScript::UpdatableFuncPtr function;
|
||||||
Ref<GDScript> script;
|
Ref<GDScript> script;
|
||||||
uint32_t h;
|
uint32_t h;
|
||||||
GDScript::UpdatableFuncPtrElement updatable_func_ptr_element;
|
|
||||||
|
|
||||||
Vector<Variant> captures;
|
Vector<Variant> captures;
|
||||||
|
|
||||||
|
@ -62,17 +61,18 @@ public:
|
||||||
StringName get_method() const override;
|
StringName get_method() const override;
|
||||||
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||||
|
|
||||||
|
GDScriptLambdaCallable(GDScriptLambdaCallable &) = delete;
|
||||||
|
GDScriptLambdaCallable(const GDScriptLambdaCallable &) = delete;
|
||||||
GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
|
GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
|
||||||
virtual ~GDScriptLambdaCallable();
|
virtual ~GDScriptLambdaCallable() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Lambda callable that references a particular object, so it can use `self` in the body.
|
// Lambda callable that references a particular object, so it can use `self` in the body.
|
||||||
class GDScriptLambdaSelfCallable : public CallableCustom {
|
class GDScriptLambdaSelfCallable : public CallableCustom {
|
||||||
GDScriptFunction *function = nullptr;
|
GDScript::UpdatableFuncPtr function;
|
||||||
Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference.
|
Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference.
|
||||||
Object *object = nullptr; // For non RefCounted objects, use a direct pointer.
|
Object *object = nullptr; // For non RefCounted objects, use a direct pointer.
|
||||||
uint32_t h;
|
uint32_t h;
|
||||||
GDScript::UpdatableFuncPtrElement updatable_func_ptr_element;
|
|
||||||
|
|
||||||
Vector<Variant> captures;
|
Vector<Variant> captures;
|
||||||
|
|
||||||
|
@ -88,9 +88,11 @@ public:
|
||||||
ObjectID get_object() const override;
|
ObjectID get_object() const override;
|
||||||
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||||
|
|
||||||
|
GDScriptLambdaSelfCallable(GDScriptLambdaSelfCallable &) = delete;
|
||||||
|
GDScriptLambdaSelfCallable(const GDScriptLambdaSelfCallable &) = delete;
|
||||||
GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
|
GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
|
||||||
GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
|
GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
|
||||||
virtual ~GDScriptLambdaSelfCallable();
|
virtual ~GDScriptLambdaSelfCallable() = default;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GDSCRIPT_LAMBDA_CALLABLE_H
|
#endif // GDSCRIPT_LAMBDA_CALLABLE_H
|
||||||
|
|
Loading…
Reference in a new issue