diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/io/marshalls.cpp | 12 | ||||
-rw-r--r-- | core/io/resource_format_binary.cpp | 2 | ||||
-rw-r--r-- | core/io/resource_loader.cpp | 2 | ||||
-rw-r--r-- | core/io/resource_saver.cpp | 2 | ||||
-rw-r--r-- | core/object.cpp | 179 | ||||
-rw-r--r-- | core/object.h | 76 | ||||
-rw-r--r-- | core/object_id.h | 1 | ||||
-rw-r--r-- | core/os/main_loop.cpp | 4 | ||||
-rw-r--r-- | core/ref_ptr.cpp | 103 | ||||
-rw-r--r-- | core/ref_ptr.h | 62 | ||||
-rw-r--r-- | core/reference.cpp | 3 | ||||
-rw-r--r-- | core/reference.h | 100 | ||||
-rw-r--r-- | core/resource.h | 1 | ||||
-rw-r--r-- | core/type_info.h | 18 | ||||
-rw-r--r-- | core/variant.cpp | 127 | ||||
-rw-r--r-- | core/variant.h | 14 | ||||
-rw-r--r-- | core/variant_call.cpp | 22 | ||||
-rw-r--r-- | core/variant_op.cpp | 66 |
18 files changed, 338 insertions, 456 deletions
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index fdce9db2a0..17edc4982c 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -802,10 +802,10 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; case Variant::OBJECT: { -#ifdef DEBUG_ENABLED + // Test for potential wrong values sent by the debugger when it breaks. - Object *obj = p_variant; - if (!obj || !ObjectDB::instance_validate(obj)) { + Object *obj = p_variant.get_validated_object(); + if (!obj) { // Object is invalid, send a NULL instead. if (buf) { encode_uint32(Variant::NIL, buf); @@ -813,7 +813,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len += 4; return OK; } -#endif // DEBUG_ENABLED + if (!p_full_objects) { flags |= ENCODE_FLAG_OBJECT_AS_ID; } @@ -1127,9 +1127,9 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } else { if (buf) { - Object *obj = p_variant; + Object *obj = p_variant.get_validated_object(); ObjectID id; - if (obj && ObjectDB::instance_validate(obj)) { + if (obj) { id = obj->get_instance_id(); } diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index 4a2bea3182..02ae5788fc 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -1573,7 +1573,7 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant &p_variant switch (p_variant.get_type()) { case Variant::OBJECT: { - RES res = p_variant.operator RefPtr(); + RES res = p_variant; if (res.is_null() || external_resources.has(res)) return; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 0ee6478fa2..6877f816e1 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -955,7 +955,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) { ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + "."); ResourceFormatLoader *crl = Object::cast_to<ResourceFormatLoader>(obj); - crl->set_script(s.get_ref_ptr()); + crl->set_script(s); ResourceLoader::add_resource_format_loader(crl); return true; diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp index b468685e4d..685d21107f 100644 --- a/core/io/resource_saver.cpp +++ b/core/io/resource_saver.cpp @@ -221,7 +221,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) { ERR_FAIL_COND_V_MSG(obj == NULL, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + "."); ResourceFormatSaver *crl = Object::cast_to<ResourceFormatSaver>(obj); - crl->set_script(s.get_ref_ptr()); + crl->set_script(s); ResourceSaver::add_resource_format_saver(crl); return true; diff --git a/core/object.cpp b/core/object.cpp index dc1dc2c41f..9a5cfe5c22 100644 --- a/core/object.cpp +++ b/core/object.cpp @@ -968,7 +968,7 @@ void Object::cancel_delete() { _predelete_ok = true; } -void Object::set_script_and_instance(const RefPtr &p_script, ScriptInstance *p_instance) { +void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) { //this function is not meant to be used in any of these ways ERR_FAIL_COND(p_script.is_null()); @@ -979,7 +979,7 @@ void Object::set_script_and_instance(const RefPtr &p_script, ScriptInstance *p_i script_instance = p_instance; } -void Object::set_script(const RefPtr &p_script) { +void Object::set_script(const Variant &p_script) { if (script == p_script) return; @@ -990,7 +990,7 @@ void Object::set_script(const RefPtr &p_script) { } script = p_script; - Ref<Script> s(script); + Ref<Script> s = script; if (!s.is_null()) { if (s->can_instance()) { @@ -1017,12 +1017,12 @@ void Object::set_script_instance(ScriptInstance *p_instance) { script_instance = p_instance; if (p_instance) - script = p_instance->get_script().get_ref_ptr(); + script = p_instance->get_script(); else - script = RefPtr(); + script = Variant(); } -RefPtr Object::get_script() const { +Variant Object::get_script() const { return script; } @@ -1911,8 +1911,8 @@ void Object::set_script_instance_binding(int p_script_language_index, void *p_da _script_instance_bindings[p_script_language_index] = p_data; } -Object::Object() { - +void Object::_construct_object(bool p_reference) { + type_is_reference = p_reference; _class_ptr = NULL; _block_signals = false; _predelete_ok = 0; @@ -1933,6 +1933,14 @@ Object::Object() { _lock_index.init(1); #endif } +Object::Object(bool p_reference) { + _construct_object(p_reference); +} + +Object::Object() { + + _construct_object(false); +} Object::~Object() { @@ -1993,96 +2001,139 @@ void postinitialize_handler(Object *p_object) { p_object->_postinitialize(); } -HashMap<ObjectID, Object *> ObjectDB::instances; -uint64_t ObjectDB::instance_counter = 1; -HashMap<Object *, ObjectID, ObjectDB::ObjectPtrHash> ObjectDB::instance_checks; -ObjectID ObjectDB::add_instance(Object *p_object) { - - ERR_FAIL_COND_V(p_object->get_instance_id().is_valid(), ObjectID()); - - rw_lock->write_lock(); - ObjectID instance_id = ObjectID(++instance_counter); - instances[instance_id] = p_object; - instance_checks[p_object] = instance_id; - - rw_lock->write_unlock(); +void ObjectDB::debug_objects(DebugFunc p_func) { - return instance_id; + spin_lock.lock(); + for (uint32_t i = 0; i < slot_count; i++) { + uint32_t slot = object_slots[i].next_free; + p_func(object_slots[slot].object); + } + spin_lock.unlock(); } -void ObjectDB::remove_instance(Object *p_object) { +void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { +} - rw_lock->write_lock(); +SpinLock ObjectDB::spin_lock; +uint32_t ObjectDB::slot_count = 0; +uint32_t ObjectDB::slot_max = 0; +ObjectDB::ObjectSlot *ObjectDB::object_slots = nullptr; +uint64_t ObjectDB::validator_counter = 0; - instances.erase(p_object->get_instance_id()); - instance_checks.erase(p_object); +int ObjectDB::get_object_count() { - rw_lock->write_unlock(); + return slot_count; } -Object *ObjectDB::get_instance(ObjectID p_instance_id) { - rw_lock->read_lock(); - Object **obj = instances.getptr(p_instance_id); - rw_lock->read_unlock(); +ObjectID ObjectDB::add_instance(Object *p_object) { - if (!obj) - return NULL; - return *obj; -} + spin_lock.lock(); + if (unlikely(slot_count == slot_max)) { -void ObjectDB::debug_objects(DebugFunc p_func) { + CRASH_COND(slot_count == (1 << OBJECTDB_SLOT_MAX_COUNT_BITS)); + + uint32_t new_slot_max = slot_max > 0 ? slot_max * 2 : 1; + object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max); + for (uint32_t i = slot_max; i < new_slot_max; i++) { + object_slots[i].object = nullptr; + object_slots[i].is_reference = false; + object_slots[i].next_free = i; + object_slots[i].validator = 0; + } + slot_max = new_slot_max; + } - rw_lock->read_lock(); + uint32_t slot = object_slots[slot_count].next_free; + if (object_slots[slot].object != nullptr) { + spin_lock.unlock(); + ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID()); + } + object_slots[slot].object = p_object; + object_slots[slot].is_reference = p_object->is_reference(); + validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK; + if (unlikely(validator_counter == 0)) { + validator_counter = 1; + } + object_slots[slot].validator = validator_counter; - const ObjectID *K = NULL; - while ((K = instances.next(K))) { + uint64_t id = validator_counter; + id <<= OBJECTDB_SLOT_MAX_COUNT_BITS; + id |= uint64_t(slot); - p_func(instances[*K]); + if (p_object->is_reference()) { + id |= OBJECTDB_REFERENCE_BIT; } - rw_lock->read_unlock(); -} + slot_count++; -void Object::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + spin_lock.unlock(); + + return ObjectID(id); } -int ObjectDB::get_object_count() { +void ObjectDB::remove_instance(Object *p_object) { + uint64_t t = p_object->get_instance_id(); + uint32_t slot = t & OBJECTDB_SLOT_MAX_COUNT_MASK; //slot is always valid on valid object - rw_lock->read_lock(); - int count = instances.size(); - rw_lock->read_unlock(); + spin_lock.lock(); - return count; -} +#ifdef DEBUG_ENABLED -RWLock *ObjectDB::rw_lock = NULL; + if (object_slots[slot].object != p_object) { + spin_lock.unlock(); + ERR_FAIL_COND(object_slots[slot].object != p_object); + } + { + uint64_t validator = (t >> OBJECTDB_SLOT_MAX_COUNT_BITS) & OBJECTDB_VALIDATOR_MASK; + if (object_slots[slot].validator != validator) { + spin_lock.unlock(); + ERR_FAIL_COND(object_slots[slot].validator != validator); + } + } + +#endif + //decrease slot count + slot_count--; + //set the free slot properly + object_slots[slot_count].next_free = slot; + //invalidate, so checks against it fail + object_slots[slot].validator = 0; + object_slots[slot].is_reference = false; + object_slots[slot].object = nullptr; + + spin_lock.unlock(); +} void ObjectDB::setup() { - rw_lock = RWLock::create(); + //nothing to do now } void ObjectDB::cleanup() { - rw_lock->write_lock(); - if (instances.size()) { + if (slot_count > 0) { + spin_lock.lock(); WARN_PRINT("ObjectDB Instances still exist!"); if (OS::get_singleton()->is_stdout_verbose()) { - const ObjectID *K = NULL; - while ((K = instances.next(K))) { + for (uint32_t i = 0; i < slot_count; i++) { + uint32_t slot = object_slots[i].next_free; + Object *obj = object_slots[slot].object; String node_name; - if (instances[*K]->is_class("Node")) - node_name = " - Node name: " + String(instances[*K]->call("get_name")); - if (instances[*K]->is_class("Resource")) - node_name = " - Resource name: " + String(instances[*K]->call("get_name")) + " Path: " + String(instances[*K]->call("get_path")); - print_line("Leaked instance: " + String(instances[*K]->get_class()) + ":" + itos(*K) + node_name); + if (obj->is_class("Node")) + node_name = " - Node name: " + String(obj->call("get_name")); + if (obj->is_class("Resource")) + node_name = " - Resource name: " + String(obj->call("get_name")) + " Path: " + String(obj->call("get_path")); + + uint64_t id = uint64_t(slot) | (uint64_t(object_slots[slot].validator) << OBJECTDB_VALIDATOR_BITS) | (object_slots[slot].is_reference ? OBJECTDB_REFERENCE_BIT : 0); + print_line("Leaked instance: " + String(obj->get_class()) + ":" + itos(id) + node_name); } } + spin_lock.unlock(); + } + + if (object_slots) { + memfree(object_slots); } - instances.clear(); - instance_checks.clear(); - rw_lock->write_unlock(); - memdelete(rw_lock); } diff --git a/core/object.h b/core/object.h index 312fe07a17..6a229afaea 100644 --- a/core/object.h +++ b/core/object.h @@ -37,6 +37,7 @@ #include "core/object_id.h" #include "core/os/rw_lock.h" #include "core/set.h" +#include "core/spin_lock.h" #include "core/variant.h" #include "core/vmap.h" @@ -488,7 +489,7 @@ private: Set<String> editor_section_folding; #endif ScriptInstance *script_instance; - RefPtr script; + Variant script; //reference does not yet exist, store it in a Dictionary metadata; mutable StringName _class_name; mutable const StringName *_class_ptr; @@ -506,9 +507,13 @@ private: void property_list_changed_notify(); + _FORCE_INLINE_ void _construct_object(bool p_reference); + friend class Reference; + bool type_is_reference = false; uint32_t instance_binding_count; void *_script_instance_bindings[MAX_SCRIPT_INSTANCE_BINDINGS]; + Object(bool p_reference); protected: virtual void _initialize_classv() { initialize_class(); } @@ -680,8 +685,8 @@ public: /* SCRIPT */ - void set_script(const RefPtr &p_script); - RefPtr get_script() const; + void set_script(const Variant &p_script); + Variant get_script() const; /* SCRIPT */ @@ -700,7 +705,7 @@ public: void set_script_instance(ScriptInstance *p_instance); _FORCE_INLINE_ ScriptInstance *get_script_instance() const { return script_instance; } - void set_script_and_instance(const RefPtr &p_script, ScriptInstance *p_instance); //some script languages can't control instance creation, so this function eases the process + void set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance); //some script languages can't control instance creation, so this function eases the process void add_user_signal(const MethodInfo &p_signal); Error emit_signal(const StringName &p_name, VARIANT_ARG_LIST); @@ -751,6 +756,7 @@ public: void clear_internal_resource_paths(); + _ALWAYS_INLINE_ bool is_reference() const { return type_is_reference; } Object(); virtual ~Object(); }; @@ -760,49 +766,63 @@ void postinitialize_handler(Object *p_object); class ObjectDB { - struct ObjectPtrHash { - - static _FORCE_INLINE_ uint32_t hash(const Object *p_obj) { - - union { - const Object *p; - unsigned long i; - } u; - u.p = p_obj; - return HashMapHasherDefault::hash((uint64_t)u.i); - } +//this needs to add up to 63, 1 bit is for reference +#define OBJECTDB_VALIDATOR_BITS 39 +#define OBJECTDB_VALIDATOR_MASK ((uint64_t(1) << OBJECTDB_VALIDATOR_BITS) - 1) +#define OBJECTDB_SLOT_MAX_COUNT_BITS 24 +#define OBJECTDB_SLOT_MAX_COUNT_MASK ((uint64_t(1) << OBJECTDB_SLOT_MAX_COUNT_BITS) - 1) +#define OBJECTDB_REFERENCE_BIT (uint64_t(1) << (OBJECTDB_SLOT_MAX_COUNT_BITS + OBJECTDB_VALIDATOR_BITS)) + + struct ObjectSlot { //128 bits per slot + uint64_t validator : OBJECTDB_VALIDATOR_BITS; + uint64_t next_free : OBJECTDB_SLOT_MAX_COUNT_BITS; + uint64_t is_reference : 1; + Object *object; }; - static HashMap<ObjectID, Object *> instances; - static HashMap<Object *, ObjectID, ObjectPtrHash> instance_checks; + static SpinLock spin_lock; + static uint32_t slot_count; + static uint32_t slot_max; + static ObjectSlot *object_slots; + static uint64_t validator_counter; - static uint64_t instance_counter; friend class Object; friend void unregister_core_types(); - - static RWLock *rw_lock; static void cleanup(); + static ObjectID add_instance(Object *p_object); static void remove_instance(Object *p_object); + friend void register_core_types(); static void setup(); public: typedef void (*DebugFunc)(Object *p_obj); - static Object *get_instance(ObjectID p_instance_id); - static void debug_objects(DebugFunc p_func); - static int get_object_count(); + _ALWAYS_INLINE_ static Object *get_instance(ObjectID p_instance_id) { + + uint64_t id = p_instance_id; + uint32_t slot = id & OBJECTDB_SLOT_MAX_COUNT_MASK; + + ERR_FAIL_COND_V(slot >= slot_max, nullptr); //this should never happen unless RID is corrupted + + spin_lock.lock(); - _FORCE_INLINE_ static bool instance_validate(Object *p_ptr) { - rw_lock->read_lock(); + uint64_t validator = (id >> OBJECTDB_SLOT_MAX_COUNT_BITS) & OBJECTDB_VALIDATOR_MASK; - bool exists = instance_checks.has(p_ptr); + if (unlikely(object_slots[slot].validator != validator)) { + spin_lock.unlock(); + return nullptr; + } + + Object *object = object_slots[slot].object; - rw_lock->read_unlock(); + spin_lock.unlock(); - return exists; + return object; } + static void debug_objects(DebugFunc p_func); + static int get_object_count(); }; //needed by macros diff --git a/core/object_id.h b/core/object_id.h index f0ff2a24f5..6ab1a3031a 100644 --- a/core/object_id.h +++ b/core/object_id.h @@ -12,6 +12,7 @@ class ObjectID { uint64_t id = 0; public: + _ALWAYS_INLINE_ bool is_reference() const { return (id & (uint64_t(1) << 63)) != 0; } _ALWAYS_INLINE_ bool is_valid() const { return id != 0; } _ALWAYS_INLINE_ bool is_null() const { return id == 0; } _ALWAYS_INLINE_ operator uint64_t() const { return id; } diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp index 5ecdd74a4b..6020c4b219 100644 --- a/core/os/main_loop.cpp +++ b/core/os/main_loop.cpp @@ -95,7 +95,7 @@ void MainLoop::input_event(const Ref<InputEvent> &p_event) { void MainLoop::init() { if (init_script.is_valid()) - set_script(init_script.get_ref_ptr()); + set_script(init_script); if (get_script_instance()) get_script_instance()->call("_initialize"); @@ -131,6 +131,6 @@ void MainLoop::finish() { if (get_script_instance()) { get_script_instance()->call("_finalize"); - set_script(RefPtr()); //clear script + set_script(Variant()); //clear script } } diff --git a/core/ref_ptr.cpp b/core/ref_ptr.cpp deleted file mode 100644 index 7e35bcc56c..0000000000 --- a/core/ref_ptr.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/*************************************************************************/ -/* ref_ptr.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "ref_ptr.h" - -#include "core/reference.h" -#include "core/resource.h" - -void RefPtr::operator=(const RefPtr &p_other) { - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - Ref<Reference> *ref_other = reinterpret_cast<Ref<Reference> *>(const_cast<char *>(&p_other.data[0])); - - *ref = *ref_other; -} - -bool RefPtr::operator==(const RefPtr &p_other) const { - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - Ref<Reference> *ref_other = reinterpret_cast<Ref<Reference> *>(const_cast<char *>(&p_other.data[0])); - - return *ref == *ref_other; -} - -bool RefPtr::operator!=(const RefPtr &p_other) const { - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - Ref<Reference> *ref_other = reinterpret_cast<Ref<Reference> *>(const_cast<char *>(&p_other.data[0])); - - return *ref != *ref_other; -} - -RefPtr::RefPtr(const RefPtr &p_other) { - - memnew_placement(&data[0], Ref<Reference>); - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - Ref<Reference> *ref_other = reinterpret_cast<Ref<Reference> *>(const_cast<char *>(&p_other.data[0])); - - *ref = *ref_other; -} - -bool RefPtr::is_null() const { - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - return ref->is_null(); -} - -RID RefPtr::get_rid() const { - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - if (ref->is_null()) - return RID(); - Resource *res = Object::cast_to<Resource>(ref->ptr()); - if (res) - return res->get_rid(); - return RID(); -} - -void RefPtr::unref() { - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - ref->unref(); -} - -RefPtr::RefPtr() { - - ERR_FAIL_COND(sizeof(Ref<Reference>) > DATASIZE); - memnew_placement(&data[0], Ref<Reference>); -} - -RefPtr::~RefPtr() { - - Ref<Reference> *ref = reinterpret_cast<Ref<Reference> *>(&data[0]); - ref->~Ref<Reference>(); -} diff --git a/core/ref_ptr.h b/core/ref_ptr.h deleted file mode 100644 index 4736106b4f..0000000000 --- a/core/ref_ptr.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* ref_ptr.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef REF_PTR_H -#define REF_PTR_H -/** - @author Juan Linietsky <reduzio@gmail.com> - * This class exists to workaround a limitation in C++ but keep the design OK. - * It's basically an opaque container of a Reference reference, so Variant can use it. -*/ - -#include "core/rid.h" - -class RefPtr { - - enum { - - DATASIZE = sizeof(void *) //*4 -ref was shrunk - }; - - mutable char data[DATASIZE]; // too much probably, virtual class + pointer -public: - bool is_null() const; - void operator=(const RefPtr &p_other); - bool operator==(const RefPtr &p_other) const; - bool operator!=(const RefPtr &p_other) const; - RID get_rid() const; - void unref(); - _FORCE_INLINE_ void *get_data() const { return data; } - RefPtr(const RefPtr &p_other); - RefPtr(); - ~RefPtr(); -}; - -#endif // REF_PTR_H diff --git a/core/reference.cpp b/core/reference.cpp index 5c211fe301..dd65ccce69 100644 --- a/core/reference.cpp +++ b/core/reference.cpp @@ -102,7 +102,8 @@ bool Reference::unreference() { return die; } -Reference::Reference() { +Reference::Reference() : + Object(true) { refcount.init(); refcount_init.init(); diff --git a/core/reference.h b/core/reference.h index d2314005b9..b01e0035a7 100644 --- a/core/reference.h +++ b/core/reference.h @@ -33,7 +33,6 @@ #include "core/class_db.h" #include "core/object.h" -#include "core/ref_ptr.h" #include "core/safe_refcount.h" class Reference : public Object { @@ -133,17 +132,9 @@ public: return reference; } - RefPtr get_ref_ptr() const { - - RefPtr refptr; - Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(refptr.get_data()); - *irr = *this; - return refptr; - }; - operator Variant() const { - return Variant(get_ref_ptr()); + return Variant(reference); } void operator=(const Ref &p_from) { @@ -165,33 +156,24 @@ public: r.reference = NULL; } - void operator=(const RefPtr &p_refptr) { + void operator=(const Variant &p_variant) { - Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(p_refptr.get_data()); - Reference *refb = irr->ptr(); - if (!refb) { - unref(); + Object *object = p_variant.get_validated_object(); + + if (object == reference) { return; } - Ref r; - r.reference = Object::cast_to<T>(refb); - ref(r); - r.reference = NULL; - } - void operator=(const Variant &p_variant) { + unref(); - RefPtr refptr = p_variant; - Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(refptr.get_data()); - Reference *refb = irr->ptr(); - if (!refb) { - unref(); + if (!object) { return; } - Ref r; - r.reference = Object::cast_to<T>(refb); - ref(r); - r.reference = NULL; + + Reference *r = Object::cast_to<Reference>(object); + if (r && r->reference()) { + reference = static_cast<T *>(r); + } } template <class T_Other> @@ -237,33 +219,19 @@ public: Ref(const Variant &p_variant) { - RefPtr refptr = p_variant; - Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(refptr.get_data()); - reference = NULL; - Reference *refb = irr->ptr(); - if (!refb) { - unref(); + Object *object = p_variant.get_validated_object(); + + if (!object) { + reference = nullptr; return; } - Ref r; - r.reference = Object::cast_to<T>(refb); - ref(r); - r.reference = NULL; - } - - Ref(const RefPtr &p_refptr) { - Ref<Reference> *irr = reinterpret_cast<Ref<Reference> *>(p_refptr.get_data()); - reference = NULL; - Reference *refb = irr->ptr(); - if (!refb) { - unref(); - return; + Reference *r = Object::cast_to<Reference>(object); + if (r && r->reference()) { + reference = static_cast<T *>(r); + } else { + reference = nullptr; } - Ref r; - r.reference = Object::cast_to<T>(refb); - ref(r); - r.reference = NULL; } inline bool is_valid() const { return reference != NULL; } @@ -340,32 +308,6 @@ struct PtrToArg<const Ref<T> &> { } }; -//this is for RefPtr - -template <> -struct PtrToArg<RefPtr> { - - _FORCE_INLINE_ static RefPtr convert(const void *p_ptr) { - - return Ref<Reference>(const_cast<Reference *>(reinterpret_cast<const Reference *>(p_ptr))).get_ref_ptr(); - } - - _FORCE_INLINE_ static void encode(RefPtr p_val, const void *p_ptr) { - - Ref<Reference> r = p_val; - *(Ref<Reference> *)p_ptr = r; - } -}; - -template <> -struct PtrToArg<const RefPtr &> { - - _FORCE_INLINE_ static RefPtr convert(const void *p_ptr) { - - return Ref<Reference>(const_cast<Reference *>(reinterpret_cast<const Reference *>(p_ptr))).get_ref_ptr(); - } -}; - #endif // PTRCALL_ENABLED #ifdef DEBUG_METHODS_ENABLED diff --git a/core/resource.h b/core/resource.h index 00d330a094..b30788010b 100644 --- a/core/resource.h +++ b/core/resource.h @@ -33,7 +33,6 @@ #include "core/class_db.h" #include "core/object.h" -#include "core/ref_ptr.h" #include "core/reference.h" #include "core/safe_refcount.h" #include "core/self_list.h" diff --git a/core/type_info.h b/core/type_info.h index b9e5b61a6a..9ca6d7fe73 100644 --- a/core/type_info.h +++ b/core/type_info.h @@ -169,24 +169,6 @@ MAKE_TYPE_INFO(IP_Address, Variant::STRING) class BSP_Tree; MAKE_TYPE_INFO(BSP_Tree, Variant::DICTIONARY) -//for RefPtr -template <> -struct GetTypeInfo<RefPtr> { - static const Variant::Type VARIANT_TYPE = Variant::OBJECT; - static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; - static inline PropertyInfo get_class_info() { - return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference"); - } -}; -template <> -struct GetTypeInfo<const RefPtr &> { - static const Variant::Type VARIANT_TYPE = Variant::OBJECT; - static const GodotTypeInfo::Metadata METADATA = GodotTypeInfo::METADATA_NONE; - static inline PropertyInfo get_class_info() { - return PropertyInfo(Variant::OBJECT, String(), PROPERTY_HINT_RESOURCE_TYPE, "Reference"); - } -}; - //objectID template <> struct GetTypeInfo<ObjectID> { diff --git a/core/variant.cpp b/core/variant.cpp index 0f04710d13..c2ffe3721f 100644 --- a/core/variant.cpp +++ b/core/variant.cpp @@ -908,6 +908,14 @@ bool Variant::is_one() const { return false; } +bool Variant::is_null() const { + if (type == OBJECT && _get_obj().obj) { + return false; + } else { + return true; + } +} + void Variant::reference(const Variant &p_variant) { switch (type) { @@ -999,7 +1007,20 @@ void Variant::reference(const Variant &p_variant) { } break; case OBJECT: { - memnew_placement(_data._mem, ObjData(p_variant._get_obj())); + memnew_placement(_data._mem, ObjData); + + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { + Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); + if (!reference->reference()) { + _get_obj().obj = nullptr; + _get_obj().id = ObjectID(); + break; + } + } + + _get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj); + _get_obj().id = p_variant._get_obj().id; + } break; case NODE_PATH: { @@ -1114,8 +1135,15 @@ void Variant::clear() { } break; case OBJECT: { + if (_get_obj().id.is_reference()) { + //we are safe that there is a reference here + Reference *reference = static_cast<Reference *>(_get_obj().obj); + if (reference->unreference()) { + memdelete(reference); + } + } _get_obj().obj = NULL; - _get_obj().ref.unref(); + _get_obj().id = ObjectID(); } break; case _RID: { // not much need probably @@ -1589,14 +1617,11 @@ String Variant::stringify(List<const void *> &stack) const { case OBJECT: { if (_get_obj().obj) { -#ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) { - //only if debugging! - if (!ObjectDB::instance_validate(_get_obj().obj)) { - return "[Deleted Object]"; - }; + + if (!_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + return "[Freed Object]"; }; -#endif + return _get_obj().obj->to_string(); } else return "[Object:null]"; @@ -1739,24 +1764,16 @@ Variant::operator NodePath() const { return NodePath(); } -Variant::operator RefPtr() const { - - if (type == OBJECT) - return _get_obj().ref; - else - return RefPtr(); -} - Variant::operator RID() const { if (type == _RID) return *reinterpret_cast<const RID *>(_data._mem); - else if (type == OBJECT && !_get_obj().ref.is_null()) { - return _get_obj().ref.get_rid(); + else if (type == OBJECT && _get_obj().obj == nullptr) { + return RID(); } else if (type == OBJECT && _get_obj().obj) { #ifdef DEBUG_ENABLED if (ScriptDebugger::get_singleton()) { - ERR_FAIL_COND_V_MSG(!ObjectDB::instance_validate(_get_obj().obj), RID(), "Invalid pointer (object was deleted)."); + ERR_FAIL_COND_V_MSG(ObjectDB::get_instance(_get_obj().id) == nullptr, RID(), "Invalid pointer (object was freed)."); }; #endif Variant::CallError ce; @@ -1777,6 +1794,25 @@ Variant::operator Object *() const { else return NULL; } + +Object *Variant::get_validated_object_with_check(bool &r_previously_freed) const { + if (type == OBJECT) { + Object *instance = ObjectDB::get_instance(_get_obj().id); + r_previously_freed = !instance && _get_obj().id != ObjectID(); + return instance; + } else { + r_previously_freed = false; + return NULL; + } +} + +Object *Variant::get_validated_object() const { + if (type == OBJECT) + return ObjectDB::get_instance(_get_obj().id); + else + return NULL; +} + Variant::operator Node *() const { if (type == OBJECT) @@ -2289,15 +2325,6 @@ Variant::Variant(const NodePath &p_node_path) { memnew_placement(_data._mem, NodePath(p_node_path)); } -Variant::Variant(const RefPtr &p_resource) { - - type = OBJECT; - memnew_placement(_data._mem, ObjData); - REF *ref = reinterpret_cast<REF *>(p_resource.get_data()); - _get_obj().obj = ref->ptr(); - _get_obj().ref = p_resource; -} - Variant::Variant(const RID &p_rid) { type = _RID; @@ -2309,7 +2336,24 @@ Variant::Variant(const Object *p_object) { type = OBJECT; memnew_placement(_data._mem, ObjData); - _get_obj().obj = const_cast<Object *>(p_object); + + if (p_object) { + + if (p_object->is_reference()) { + Reference *reference = const_cast<Reference *>(static_cast<const Reference *>(p_object)); + if (!reference->init_ref()) { + _get_obj().obj = nullptr; + _get_obj().id = ObjectID(); + return; + } + } + + _get_obj().obj = const_cast<Object *>(p_object); + _get_obj().id = p_object->get_instance_id(); + } else { + _get_obj().obj = nullptr; + _get_obj().id = ObjectID(); + } } Variant::Variant(const Dictionary &p_dictionary) { @@ -2620,7 +2664,26 @@ void Variant::operator=(const Variant &p_variant) { } break; case OBJECT: { - *reinterpret_cast<ObjData *>(_data._mem) = p_variant._get_obj(); + if (_get_obj().id.is_reference()) { + //we are safe that there is a reference here + Reference *reference = static_cast<Reference *>(_get_obj().obj); + if (reference->unreference()) { + memdelete(reference); + } + } + + if (p_variant._get_obj().obj && p_variant._get_obj().id.is_reference()) { + Reference *reference = static_cast<Reference *>(p_variant._get_obj().obj); + if (!reference->reference()) { + _get_obj().obj = nullptr; + _get_obj().id = ObjectID(); + break; + } + } + + _get_obj().obj = const_cast<Object *>(p_variant._get_obj().obj); + _get_obj().id = p_variant._get_obj().id; + } break; case NODE_PATH: { @@ -3131,7 +3194,7 @@ bool Variant::hash_compare(const Variant &p_variant) const { bool Variant::is_ref() const { - return type == OBJECT && !_get_obj().ref.is_null(); + return type == OBJECT && _get_obj().id.is_reference(); } Vector<Variant> varray() { diff --git a/core/variant.h b/core/variant.h index d8007f9e12..bb3840932d 100644 --- a/core/variant.h +++ b/core/variant.h @@ -46,11 +46,9 @@ #include "core/node_path.h" #include "core/object_id.h" #include "core/pool_vector.h" -#include "core/ref_ptr.h" #include "core/rid.h" #include "core/ustring.h" -class RefPtr; class Object; class Node; // helper class Control; // helper @@ -128,12 +126,12 @@ private: struct ObjData { + ObjectID id; Object *obj; - RefPtr ref; }; - _FORCE_INLINE_ ObjData &_get_obj(); - _FORCE_INLINE_ const ObjData &_get_obj() const; + _ALWAYS_INLINE_ ObjData &_get_obj(); + _ALWAYS_INLINE_ const ObjData &_get_obj() const; union { bool _bool; @@ -162,6 +160,7 @@ public: bool is_shared() const; bool is_zero() const; bool is_one() const; + bool is_null() const; operator bool() const; operator signed int() const; @@ -197,7 +196,6 @@ public: operator Color() const; operator NodePath() const; - operator RefPtr() const; operator RID() const; operator Object *() const; @@ -235,6 +233,9 @@ public: operator IP_Address() const; + Object *get_validated_object() const; + Object *get_validated_object_with_check(bool &r_previously_freed) const; + Variant(bool p_bool); Variant(signed int p_int); // real one Variant(unsigned int p_int); @@ -267,7 +268,6 @@ public: Variant(const Transform &p_transform); Variant(const Color &p_color); Variant(const NodePath &p_node_path); - Variant(const RefPtr &p_resource); Variant(const RID &p_rid); Variant(const Object *p_object); Variant(const Dictionary &p_dictionary); diff --git a/core/variant_call.cpp b/core/variant_call.cpp index f088705cdd..ac995d1c78 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -1099,12 +1099,9 @@ void Variant::call_ptr(const StringName &p_method, const Variant **p_args, int p return; } #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) { - //only if debugging! - if (!ObjectDB::instance_validate(obj)) { - r_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL; - return; - } + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + r_error.error = CallError::CALL_ERROR_INSTANCE_IS_NULL; + return; } #endif @@ -1274,18 +1271,11 @@ Variant Variant::construct(const Variant::Type p_type, const Variant **p_args, i bool Variant::has_method(const StringName &p_method) const { if (type == OBJECT) { - Object *obj = operator Object *(); + Object *obj = get_validated_object(); if (!obj) return false; -#ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton()) { - if (ObjectDB::instance_validate(obj)) { -#endif - return obj->has_method(p_method); -#ifdef DEBUG_ENABLED - } - } -#endif + + return obj->has_method(p_method); } const _VariantCall::TypeFunc &tf = _VariantCall::type_funcs[type]; diff --git a/core/variant_op.cpp b/core/variant_op.cpp index 6caa224cfe..c7a52b0347 100644 --- a/core/variant_op.cpp +++ b/core/variant_op.cpp @@ -1515,7 +1515,7 @@ void Variant::set_named(const StringName &p_index, const Variant &p_value, bool #ifdef DEBUG_ENABLED if (!_get_obj().obj) { break; - } else if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null() && !ObjectDB::instance_validate(_get_obj().obj)) { + } else if (ScriptDebugger::get_singleton() && ObjectDB::get_instance(_get_obj().id) == nullptr) { break; } @@ -1684,7 +1684,7 @@ Variant Variant::get_named(const StringName &p_index, bool *r_valid) const { return "Instance base is null."; } else { - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null() && !ObjectDB::instance_validate(_get_obj().obj)) { + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { if (r_valid) *r_valid = false; return "Attempted use of stray pointer object."; @@ -2172,13 +2172,11 @@ void Variant::set(const Variant &p_index, const Variant &p_value, bool *r_valid) if (obj) { #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) { + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { - if (!ObjectDB::instance_validate(obj)) { - WARN_PRINT("Attempted use of stray pointer object."); - valid = false; - return; - } + WARN_PRINT("Attempted use of previously freed pointer object."); + valid = false; + return; } #endif @@ -2546,12 +2544,10 @@ Variant Variant::get(const Variant &p_index, bool *r_valid) const { if (obj) { #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) { - //only if debugging! - if (!ObjectDB::instance_validate(obj)) { - valid = false; - return "Attempted get on stray pointer."; - } + + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + valid = false; + return "Attempted get on previously freed instance."; } #endif @@ -2611,15 +2607,14 @@ bool Variant::in(const Variant &p_index, bool *r_valid) const { bool valid = false; #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) { - //only if debugging! - if (!ObjectDB::instance_validate(obj)) { - if (r_valid) { - *r_valid = false; - } - return true; // Attempted get on stray pointer. + + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + if (r_valid) { + *r_valid = false; } + return true; // Attempted get on stray pointer. } + #endif if (p_index.get_type() != Variant::STRING) { @@ -2883,13 +2878,12 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const { Object *obj = _get_obj().obj; if (obj) { #ifdef DEBUG_ENABLED - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) { - //only if debugging! - if (!ObjectDB::instance_validate(obj)) { - WARN_PRINT("Attempted get_property list on stray pointer."); - return; - } + + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { + WARN_PRINT("Attempted get_property list on previously freed instance."); + return; } + #endif obj->get_property_list(p_list); @@ -2961,16 +2955,18 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const { } break; case OBJECT: { -#ifdef DEBUG_ENABLED if (!_get_obj().obj) { valid = false; return false; } - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null() && !ObjectDB::instance_validate(_get_obj().obj)) { +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } + #endif Variant::CallError ce; ce.error = Variant::CallError::CALL_OK; @@ -3129,16 +3125,18 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const { } break; case OBJECT: { -#ifdef DEBUG_ENABLED if (!_get_obj().obj) { valid = false; return false; } - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null() && !ObjectDB::instance_validate(_get_obj().obj)) { +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { valid = false; return false; } + #endif Variant::CallError ce; ce.error = Variant::CallError::CALL_OK; @@ -3288,16 +3286,16 @@ Variant Variant::iter_get(const Variant &r_iter, bool &r_valid) const { } break; case OBJECT: { -#ifdef DEBUG_ENABLED if (!_get_obj().obj) { r_valid = false; return Variant(); } - - if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null() && !ObjectDB::instance_validate(_get_obj().obj)) { +#ifdef DEBUG_ENABLED + if (ScriptDebugger::get_singleton() && !_get_obj().id.is_reference() && ObjectDB::get_instance(_get_obj().id) == nullptr) { r_valid = false; return Variant(); } + #endif Variant::CallError ce; ce.error = Variant::CallError::CALL_OK; |