Skip to content

Commit

Permalink
Merge pull request #50290 from reduz/redo-instance-bindings
Browse files Browse the repository at this point in the history
Redo how instance bindings work
  • Loading branch information
akien-mga authored Jul 9, 2021
2 parents 96e17e4 + 4469144 commit ca2fda6
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 62 deletions.
6 changes: 6 additions & 0 deletions core/extension/gdnative_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down Expand Up @@ -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;
Expand Down
11 changes: 11 additions & 0 deletions core/extension/gdnative_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down
61 changes: 30 additions & 31 deletions core/object/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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);
}
}

Expand All @@ -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--;
}
}
Expand Down
35 changes: 26 additions & 9 deletions core/object/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,10 +480,6 @@ class Object {
};

private:
enum {
MAX_SCRIPT_INSTANCE_BINDINGS = 8
};

#ifdef DEBUG_ENABLED
friend struct _ObjectDebugLock;
#endif
Expand Down Expand Up @@ -542,12 +538,35 @@ class Object {

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; }
Expand Down Expand Up @@ -785,9 +804,7 @@ class Object {
#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();

Expand Down
19 changes: 4 additions & 15 deletions core/object/ref_counted.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion modules/gdnative/nativescript/godot_nativescript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ void GDAPI godot_nativescript_unregister_instance_binding_data_functions(int p_i
}

void GDAPI *godot_nativescript_get_instance_binding_data(int p_idx, godot_object *p_object) {
return NativeScriptLanguage::get_singleton()->get_instance_binding_data(p_idx, (Object *)p_object);
return nullptr;
}

void GDAPI godot_nativescript_profiling_add_data(const char *p_signature, uint64_t p_time) {
Expand Down
13 changes: 13 additions & 0 deletions modules/gdnative/nativescript/nativescript.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1258,6 +1258,8 @@ void NativeScriptLanguage::unregister_binding_functions(int p_idx) {
}

void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_object) {
return nullptr;
#if 0
ERR_FAIL_INDEX_V(p_idx, binding_functions.size(), nullptr);

ERR_FAIL_COND_V_MSG(!binding_functions[p_idx].first, nullptr, "Tried to get binding data for a nativescript binding that does not exist.");
Expand Down Expand Up @@ -1287,9 +1289,12 @@ void *NativeScriptLanguage::get_instance_binding_data(int p_idx, Object *p_objec
}

return (*binding_data)[p_idx];
#endif
}

void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) {
return nullptr;
#if 0
Vector<void *> *binding_data = new Vector<void *>;

binding_data->resize(binding_functions.size());
Expand All @@ -1301,9 +1306,11 @@ void *NativeScriptLanguage::alloc_instance_binding_data(Object *p_object) {
binding_instances.insert(binding_data);

return (void *)binding_data;
#endif
}

void NativeScriptLanguage::free_instance_binding_data(void *p_data) {
#if 0
if (!p_data) {
return;
}
Expand All @@ -1323,9 +1330,11 @@ void NativeScriptLanguage::free_instance_binding_data(void *p_data) {
binding_instances.erase(&binding_data);

delete &binding_data;
#endif
}

void NativeScriptLanguage::refcount_incremented_instance_binding(Object *p_object) {
#if 0
void *data = p_object->get_script_instance_binding(lang_idx);

if (!data) {
Expand All @@ -1347,9 +1356,11 @@ void NativeScriptLanguage::refcount_incremented_instance_binding(Object *p_objec
binding_functions[i].second.refcount_incremented_instance_binding(binding_data[i], p_object);
}
}
#endif
}

bool NativeScriptLanguage::refcount_decremented_instance_binding(Object *p_object) {
#if 0
void *data = p_object->get_script_instance_binding(lang_idx);

if (!data) {
Expand All @@ -1375,6 +1386,8 @@ bool NativeScriptLanguage::refcount_decremented_instance_binding(Object *p_objec
}

return can_die;
#endif
return false;
}

void NativeScriptLanguage::set_global_type_tag(int p_idx, StringName p_class_name, const void *p_type_tag) {
Expand Down
14 changes: 11 additions & 3 deletions modules/mono/csharp_script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1510,6 +1510,7 @@ void CSharpLanguage::free_instance_binding_data(void *p_data) {
}

void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
#if 0
RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);

#ifdef DEBUG_ENABLED
Expand Down Expand Up @@ -1544,9 +1545,11 @@ void CSharpLanguage::refcount_incremented_instance_binding(Object *p_object) {
gchandle.release();
gchandle = strong_gchandle;
}
#endif
}

bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
#if 0
RefCounted *rc_owner = Object::cast_to<RefCounted>(p_object);

#ifdef DEBUG_ENABLED
Expand Down Expand Up @@ -1586,6 +1589,8 @@ bool CSharpLanguage::refcount_decremented_instance_binding(Object *p_object) {
}

return refcount == 0;
#endif
return false;
}

CSharpInstance *CSharpInstance::create_for_managed_type(Object *p_owner, CSharpScript *p_script, const MonoGCHandleData &p_gchandle) {
Expand Down Expand Up @@ -2264,8 +2269,10 @@ CSharpInstance::~CSharpInstance() {
// Otherwise, the unsafe reference debug checks will incorrectly detect a bug.
bool die = _unreference_owner_unsafe();
CRASH_COND(die); // `owner_keep_alive` holds a reference, so it can't die

#if 0
void *data = owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());


CRASH_COND(data == nullptr);

CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
Expand All @@ -2283,6 +2290,7 @@ CSharpInstance::~CSharpInstance() {
#ifdef DEBUG_ENABLED
// The "instance binding" holds a reference so the refcount should be at least 2 before `scope_keep_owner_alive` goes out of scope
CRASH_COND(rc_owner->reference_get_count() <= 1);
#endif
#endif
}

Expand Down Expand Up @@ -3101,7 +3109,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
// Hold it alive. Important if we have to dispose a script instance binding before creating the CSharpInstance.
ref = Ref<RefCounted>(static_cast<RefCounted *>(p_owner));
}

#if 0
// If the object had a script instance binding, dispose it before adding the CSharpInstance
if (p_owner->has_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index())) {
void *data = p_owner->get_script_instance_binding(CSharpLanguage::get_singleton()->get_language_index());
Expand All @@ -3123,7 +3131,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
script_binding.inited = false;
}
}

#endif
CSharpInstance *instance = memnew(CSharpInstance(Ref<CSharpScript>(this)));
instance->base_ref_counted = p_is_ref_counted;
instance->owner = p_owner;
Expand Down
Loading

0 comments on commit ca2fda6

Please sign in to comment.