summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2021-07-09 23:25:33 +0200
committerGitHub <noreply@github.com>2021-07-09 23:25:33 +0200
commitca2fda629fcb1a0c7aa9945a2dd80bde993d0ac2 (patch)
tree4574d5d9de3fdb35c3d61a15fded5671dd44de92 /core
parent96e17e4ea1e6b2c8c9af28043c580fd81a7d50e5 (diff)
parent44691448911f1d29d4d79dbdd5553734761e57c4 (diff)
Merge pull request #50290 from reduz/redo-instance-bindings
Redo how instance bindings work
Diffstat (limited to 'core')
-rw-r--r--core/extension/gdnative_interface.cpp6
-rw-r--r--core/extension/gdnative_interface.h11
-rw-r--r--core/object/object.cpp61
-rw-r--r--core/object/object.h35
-rw-r--r--core/object/ref_counted.cpp19
5 files changed, 77 insertions, 55 deletions
diff --git a/core/extension/gdnative_interface.cpp b/core/extension/gdnative_interface.cpp
index 324933d7b7..8f68b8d848 100644
--- a/core/extension/gdnative_interface.cpp
+++ b/core/extension/gdnative_interface.cpp
@@ -520,6 +520,11 @@ static GDNativeObjectPtr gdnative_global_get_singleton(const char *p_name) {
return (GDNativeObjectPtr)Engine::get_singleton()->get_singleton_object(String(p_name));
}
+static void *gdnative_object_get_instance_binding(GDNativeObjectPtr p_instance, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks) {
+ Object *o = (Object *)p_instance;
+ return o->get_instance_binding(p_token, p_callbacks);
+}
+
static GDNativeObjectPtr gdnative_object_get_instance_from_id(GDObjectInstanceID p_instance_id) {
return (GDNativeObjectPtr)ObjectDB::get_instance(ObjectID(p_instance_id));
}
@@ -665,6 +670,7 @@ void gdnative_setup_interface(GDNativeInterface *p_interface) {
gdni.object_method_bind_ptrcall = gdnative_object_method_bind_ptrcall;
gdni.object_destroy = gdnative_object_destroy;
gdni.global_get_singleton = gdnative_global_get_singleton;
+ gdni.object_get_instance_binding = gdnative_object_get_instance_binding;
gdni.object_cast_to = gdnative_object_cast_to;
gdni.object_get_instance_from_id = gdnative_object_get_instance_from_id;
diff --git a/core/extension/gdnative_interface.h b/core/extension/gdnative_interface.h
index 318912e889..c1ebb3e76a 100644
--- a/core/extension/gdnative_interface.h
+++ b/core/extension/gdnative_interface.h
@@ -171,6 +171,16 @@ typedef void (*GDNativePtrUtilityFunction)(GDNativeTypePtr r_return, const GDNat
typedef GDNativeObjectPtr (*GDNativeClassConstructor)();
+typedef void *(*GDNativeInstanceBindingCreateCallback)(void *p_token, void *p_instance);
+typedef void (*GDNativeInstanceBindingFreeCallback)(void *p_token, void *p_instance, void *p_binding);
+typedef GDNativeBool (*GDNativeInstanceBindingReferenceCallback)(void *p_token, void *p_instance, GDNativeBool p_reference);
+
+struct GDNativeInstanceBindingCallbacks {
+ GDNativeInstanceBindingCreateCallback create_callback;
+ GDNativeInstanceBindingFreeCallback free_callback;
+ GDNativeInstanceBindingReferenceCallback reference_callback;
+};
+
/* EXTENSION CLASSES */
typedef void *GDExtensionClassInstancePtr;
@@ -373,6 +383,7 @@ typedef struct {
void (*object_method_bind_ptrcall)(GDNativeMethodBindPtr p_method_bind, GDNativeObjectPtr p_instance, const GDNativeTypePtr *p_args, GDNativeTypePtr r_ret);
void (*object_destroy)(GDNativeObjectPtr p_o);
GDNativeObjectPtr (*global_get_singleton)(const char *p_name);
+ void *(*object_get_instance_binding)(GDNativeObjectPtr p_o, void *p_token, GDNativeInstanceBindingCallbacks *p_callbacks);
GDNativeObjectPtr (*object_cast_to)(const GDNativeObjectPtr p_object, void *p_class_tag);
GDNativeObjectPtr (*object_get_instance_from_id)(GDObjectInstanceID p_instance_id);
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;