Skip to content

Commit

Permalink
Merge pull request #36189 from reduz/object-id-refactor
Browse files Browse the repository at this point in the history
Changed logic and optimized ObjectID in ObjectDB and Variant, removed…
  • Loading branch information
akien-mga authored Feb 15, 2020
2 parents 53cf289 + 867d073 commit 264f20f
Show file tree
Hide file tree
Showing 51 changed files with 432 additions and 559 deletions.
12 changes: 6 additions & 6 deletions core/io/marshalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -802,18 +802,18 @@ 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);
}
r_len += 4;
return OK;
}
#endif // DEBUG_ENABLED

if (!p_full_objects) {
flags |= ENCODE_FLAG_OBJECT_AS_ID;
}
Expand Down Expand Up @@ -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();
}

Expand Down
2 changes: 1 addition & 1 deletion core/io/resource_format_binary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion core/io/resource_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion core/io/resource_saver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
179 changes: 115 additions & 64 deletions core/object.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand All @@ -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;
Expand All @@ -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()) {
Expand All @@ -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;
}
Expand Down Expand Up @@ -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;
Expand All @@ -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() {

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

0 comments on commit 264f20f

Please sign in to comment.