diff options
author | reduz <reduzio@gmail.com> | 2021-07-08 16:16:02 -0300 |
---|---|---|
committer | reduz <reduzio@gmail.com> | 2021-07-08 17:08:12 -0300 |
commit | 44691448911f1d29d4d79dbdd5553734761e57c4 (patch) | |
tree | e94aef364ad141c1e96cb775eec1788b03bd8301 /core/object | |
parent | d4e5fe6c44cecccd4f925707ccd5bbe1511184e5 (diff) |
Redo how instance bindings work
* The harcoded 8 slots are no more and impose limits in the new extension system.
* New system is limitless, although it will impose small performance hit with a mutex.
* Use a token to request the instance binding.
**Warning**: Mono will most likely break as a result of this, will need to be modified to use the new system.
Diffstat (limited to 'core/object')
-rw-r--r-- | core/object/object.cpp | 61 | ||||
-rw-r--r-- | core/object/object.h | 35 | ||||
-rw-r--r-- | core/object/ref_counted.cpp | 19 |
3 files changed, 60 insertions, 55 deletions
diff --git a/core/object/object.cpp b/core/object/object.cpp index 1c8db89e5e..296d876701 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1769,42 +1769,41 @@ uint32_t Object::get_edited_version() const { } #endif -void *Object::get_script_instance_binding(int p_script_language_index) { -#ifdef DEBUG_ENABLED - ERR_FAIL_INDEX_V(p_script_language_index, MAX_SCRIPT_INSTANCE_BINDINGS, nullptr); -#endif - - //it's up to the script language to make this thread safe, if the function is called twice due to threads being out of sync - //just return the same pointer. - //if you want to put a big lock in the entire function and keep allocated pointers in a map or something, feel free to do it - //as it should not really affect performance much (won't be called too often), as in far most cases the condition below will be false afterwards - - if (!_script_instance_bindings[p_script_language_index]) { - void *script_data = ScriptServer::get_language(p_script_language_index)->alloc_instance_binding_data(this); - if (script_data) { - instance_binding_count.increment(); - _script_instance_bindings[p_script_language_index] = script_data; +void *Object::get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks) { + void *binding = nullptr; + _instance_binding_mutex.lock(); + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].token == p_token) { + binding = _instance_bindings[i].binding; + break; } } + if (unlikely(!binding)) { + uint32_t current_size = next_power_of_2(_instance_binding_count); + uint32_t new_size = next_power_of_2(_instance_binding_count + 1); - return _script_instance_bindings[p_script_language_index]; -} + if (current_size == 0 || new_size > current_size) { + _instance_bindings = (InstanceBinding *)memrealloc(_instance_bindings, new_size * sizeof(InstanceBinding)); + } -bool Object::has_script_instance_binding(int p_script_language_index) { - return _script_instance_bindings[p_script_language_index] != nullptr; -} + _instance_bindings[_instance_binding_count].free_callback = p_callbacks->free_callback; + _instance_bindings[_instance_binding_count].reference_callback = p_callbacks->reference_callback; + _instance_bindings[_instance_binding_count].token = p_token; -void Object::set_script_instance_binding(int p_script_language_index, void *p_data) { -#ifdef DEBUG_ENABLED - CRASH_COND(_script_instance_bindings[p_script_language_index] != nullptr); -#endif - _script_instance_bindings[p_script_language_index] = p_data; + binding = p_callbacks->create_callback(p_token, this); + _instance_bindings[_instance_binding_count].binding = binding; + + _instance_binding_count++; + } + + _instance_binding_mutex.unlock(); + + return binding; } void Object::_construct_object(bool p_reference) { type_is_reference = p_reference; _instance_id = ObjectDB::add_instance(this); - memset(_script_instance_bindings, 0, sizeof(void *) * MAX_SCRIPT_INSTANCE_BINDINGS); ClassDB::instance_get_native_extension_data(&_extension, &_extension_instance); @@ -1864,12 +1863,13 @@ Object::~Object() { _instance_id = ObjectID(); _predelete_ok = 2; - if (!ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - ScriptServer::get_language(i)->free_instance_binding_data(_script_instance_bindings[i]); + if (_instance_bindings != nullptr) { + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].free_callback) { + _instance_bindings[i].free_callback(_instance_bindings[i].token, _instance_bindings[i].binding, this); } } + memfree(_instance_bindings); } } @@ -1887,7 +1887,6 @@ void ObjectDB::debug_objects(DebugFunc p_func) { for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) { if (object_slots[i].validator) { p_func(object_slots[i].object); - count--; } } diff --git a/core/object/object.h b/core/object/object.h index e6eb6d1aaf..8389d80afc 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -480,10 +480,6 @@ public: }; private: - enum { - MAX_SCRIPT_INSTANCE_BINDINGS = 8 - }; - #ifdef DEBUG_ENABLED friend struct _ObjectDebugLock; #endif @@ -542,12 +538,35 @@ private: friend class RefCounted; bool type_is_reference = false; - SafeNumeric<uint32_t> instance_binding_count; - void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; + + std::mutex _instance_binding_mutex; + struct InstanceBinding { + void *binding; + void *token; + GDNativeInstanceBindingFreeCallback free_callback = nullptr; + GDNativeInstanceBindingReferenceCallback reference_callback = nullptr; + }; + InstanceBinding *_instance_bindings = nullptr; + uint32_t _instance_binding_count = 0; Object(bool p_reference); protected: + _FORCE_INLINE_ bool _instance_binding_reference(bool p_reference) { + bool can_die = true; + if (_instance_bindings) { + _instance_binding_mutex.lock(); + for (uint32_t i = 0; i < _instance_binding_count; i++) { + if (_instance_bindings[i].reference_callback) { + if (!_instance_bindings[i].reference_callback(_instance_bindings[i].token, _instance_bindings[i].binding, p_reference)) { + can_die = false; + } + } + } + _instance_binding_mutex.unlock(); + } + return can_die; + } friend class NativeExtensionMethodBind; _ALWAYS_INLINE_ const ObjectNativeExtension *_get_extension() const { return _extension; } _ALWAYS_INLINE_ GDExtensionClassInstancePtr _get_extension_instance() const { return _extension_instance; } @@ -785,9 +804,7 @@ public: #endif //used by script languages to store binding data - void *get_script_instance_binding(int p_script_language_index); - bool has_script_instance_binding(int p_script_language_index); - void set_script_instance_binding(int p_script_language_index, void *p_data); + void *get_instance_binding(void *p_token, const GDNativeInstanceBindingCallbacks *p_callbacks); void clear_internal_resource_paths(); diff --git a/core/object/ref_counted.cpp b/core/object/ref_counted.cpp index 9862624972..2833f774dc 100644 --- a/core/object/ref_counted.cpp +++ b/core/object/ref_counted.cpp @@ -65,13 +65,8 @@ bool RefCounted::reference() { if (_get_extension() && _get_extension()->reference) { _get_extension()->reference(_get_extension_instance()); } - if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - ScriptServer::get_language(i)->refcount_incremented_instance_binding(this); - } - } - } + + _instance_binding_reference(true); } return success; @@ -89,14 +84,8 @@ bool RefCounted::unreference() { if (_get_extension() && _get_extension()->unreference) { _get_extension()->unreference(_get_extension_instance()); } - if (instance_binding_count.get() > 0 && !ScriptServer::are_languages_finished()) { - for (int i = 0; i < MAX_SCRIPT_INSTANCE_BINDINGS; i++) { - if (_script_instance_bindings[i]) { - bool script_ret = ScriptServer::get_language(i)->refcount_decremented_instance_binding(this); - die = die && script_ret; - } - } - } + + die = die && _instance_binding_reference(false); } return die; |