Skip to content

Commit 73d9280

Browse files
committed
PR: godotengine/godot#98469 backportored to 4.3
1 parent ab0a573 commit 73d9280

File tree

8 files changed

+359
-153
lines changed

8 files changed

+359
-153
lines changed

core/object/object.cpp

Lines changed: 150 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -614,7 +614,11 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal
614614
return Variant();
615615
}
616616

617-
StringName method = *p_args[0];
617+
if (p_args[0]->get_type() == Variant::STRING_NAME) {
618+
const StringName &method = *VariantInternal::get_string_name(p_args[0]);
619+
return callp(method, &p_args[1], p_argcount - 1, r_error);
620+
}
621+
const StringName method = *p_args[0];
618622

619623
return callp(method, &p_args[1], p_argcount - 1, r_error);
620624
}
@@ -635,9 +639,16 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call
635639

636640
r_error.error = Callable::CallError::CALL_OK;
637641

638-
StringName method = *p_args[0];
642+
const StringName *method_ptr;
643+
StringName method;
644+
if (p_args[0]->get_type() == Variant::STRING_NAME) {
645+
method_ptr = VariantInternal::get_string_name(p_args[0]);
646+
} else {
647+
method = StringName(*p_args[0]);
648+
method_ptr = &method;
649+
}
639650

640-
MessageQueue::get_singleton()->push_callp(get_instance_id(), method, &p_args[1], p_argcount - 1, true);
651+
MessageQueue::get_singleton()->push_callp(get_instance_id(), *method_ptr, &p_args[1], p_argcount - 1, true);
641652

642653
return Variant();
643654
}
@@ -2138,15 +2149,17 @@ void postinitialize_handler(Object *p_object) {
21382149
}
21392150

21402151
void ObjectDB::debug_objects(DebugFunc p_func) {
2141-
spin_lock.lock();
2152+
mutex.lock();
21422153

2143-
for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
2144-
if (object_slots[i].validator) {
2145-
p_func(object_slots[i].object);
2146-
count--;
2154+
for (uint32_t i = 1; i < block_count; i++) {
2155+
for (uint32_t j = 0; j < blocks_max_sizes[i]; j++) {
2156+
if (blocks[i][j].validator) {
2157+
Object *obj = blocks[i][j].object;
2158+
p_func(obj);
2159+
}
21472160
}
21482161
}
2149-
spin_lock.unlock();
2162+
mutex.unlock();
21502163
}
21512164

21522165
#ifdef TOOLS_ENABLED
@@ -2195,99 +2208,151 @@ void Object::get_argument_options(const StringName &p_function, int p_idx, List<
21952208
}
21962209
#endif
21972210

2198-
SpinLock ObjectDB::spin_lock;
2211+
BinaryMutex ObjectDB::mutex;
21992212
uint32_t ObjectDB::slot_count = 0;
2213+
uint32_t ObjectDB::block_count = 0;
22002214
uint32_t ObjectDB::slot_max = 0;
2201-
ObjectDB::ObjectSlot *ObjectDB::object_slots = nullptr;
2215+
uint32_t ObjectDB::block_max = 0;
22022216
uint64_t ObjectDB::validator_counter = 0;
22032217

2218+
const uint32_t ObjectDB::blocks_max_sizes[OBJECTDB_MAX_BLOCKS] = {
2219+
0,
2220+
128,
2221+
256,
2222+
512,
2223+
1024,
2224+
1536,
2225+
2304,
2226+
3456,
2227+
5184,
2228+
7776,
2229+
11664,
2230+
17496,
2231+
26244,
2232+
39366,
2233+
59049,
2234+
88573,
2235+
132859,
2236+
199288,
2237+
298932,
2238+
448398,
2239+
672597,
2240+
1008895,
2241+
1513342,
2242+
2270013,
2243+
3405019,
2244+
5107528,
2245+
7661292,
2246+
11491938,
2247+
17237907,
2248+
25856860,
2249+
38785290,
2250+
67108864,
2251+
};
2252+
2253+
ObjectDB::ObjectSlot *ObjectDB::blocks[OBJECTDB_MAX_BLOCKS] = { nullptr };
2254+
22042255
int ObjectDB::get_object_count() {
22052256
return slot_count;
22062257
}
22072258

22082259
ObjectID ObjectDB::add_instance(Object *p_object) {
2209-
spin_lock.lock();
2210-
if (unlikely(slot_count == slot_max)) {
2260+
mutex.lock();
2261+
if (slot_count == blocks_max_sizes[block_count] && blocks[block_count + 1] != nullptr) {
2262+
slot_count = 0;
2263+
block_count++;
2264+
}
2265+
if (unlikely(slot_count == blocks_max_sizes[block_max])) {
2266+
block_max++;
2267+
CRASH_COND(block_max == OBJECTDB_MAX_BLOCKS);
22112268
CRASH_COND(slot_count == (1 << OBJECTDB_SLOT_MAX_COUNT_BITS));
2212-
2213-
uint32_t new_slot_max = slot_max > 0 ? slot_max * 2 : 1;
2214-
object_slots = (ObjectSlot *)memrealloc(object_slots, sizeof(ObjectSlot) * new_slot_max);
2215-
for (uint32_t i = slot_max; i < new_slot_max; i++) {
2216-
object_slots[i].object = nullptr;
2217-
object_slots[i].is_ref_counted = false;
2218-
object_slots[i].next_free = i;
2219-
object_slots[i].validator = 0;
2269+
blocks[block_max] = (ObjectSlot *)memalloc(sizeof(ObjectSlot) * blocks_max_sizes[block_max]);
2270+
uint32_t new_slot_max = blocks_max_sizes[block_max];
2271+
for (uint32_t i = 0; i < new_slot_max; i++) {
2272+
blocks[block_max][i].object = nullptr;
2273+
blocks[block_max][i].is_ref_counted = false;
2274+
blocks[block_max][i].next_free.block_number = block_max;
2275+
blocks[block_max][i].next_free.block_position = i;
2276+
blocks[block_max][i].validator = 0;
22202277
}
22212278
slot_max = new_slot_max;
2279+
block_count = block_max;
2280+
slot_count = 0;
22222281
}
22232282

2224-
uint32_t slot = object_slots[slot_count].next_free;
2225-
if (object_slots[slot].object != nullptr) {
2226-
spin_lock.unlock();
2227-
ERR_FAIL_COND_V(object_slots[slot].object != nullptr, ObjectID());
2283+
NextFree slot = blocks[block_count][slot_count].next_free;
2284+
Object *o = blocks[slot.block_number][slot.block_position].object;
2285+
if (o != nullptr) {
2286+
mutex.unlock();
2287+
ERR_FAIL_COND_V(o != nullptr, ObjectID());
22282288
}
2229-
object_slots[slot].object = p_object;
2230-
object_slots[slot].is_ref_counted = p_object->is_ref_counted();
2289+
blocks[slot.block_number][slot.block_position].object = p_object;
2290+
blocks[slot.block_number][slot.block_position].is_ref_counted = p_object->is_ref_counted();
22312291
validator_counter = (validator_counter + 1) & OBJECTDB_VALIDATOR_MASK;
22322292
if (unlikely(validator_counter == 0)) {
22332293
validator_counter = 1;
22342294
}
2235-
object_slots[slot].validator = validator_counter;
2295+
blocks[slot.block_number][slot.block_position].validator = validator_counter;
22362296

22372297
uint64_t id = validator_counter;
2238-
id <<= OBJECTDB_SLOT_MAX_COUNT_BITS;
2239-
id |= uint64_t(slot);
2298+
id <<= OBJECTDB_SLOT_MAX_POSITION_BITS;
2299+
id |= uint64_t(slot.position);
22402300

22412301
if (p_object->is_ref_counted()) {
22422302
id |= OBJECTDB_REFERENCE_BIT;
22432303
}
22442304

22452305
slot_count++;
22462306

2247-
spin_lock.unlock();
2307+
mutex.unlock();
22482308

22492309
return ObjectID(id);
22502310
}
22512311

22522312
void ObjectDB::remove_instance(Object *p_object) {
22532313
uint64_t t = p_object->get_instance_id();
2254-
uint32_t slot = t & OBJECTDB_SLOT_MAX_COUNT_MASK; //slot is always valid on valid object
2314+
NextFree slot;
2315+
slot.position = t & OBJECTDB_SLOT_MAX_POSITION_MASK;
22552316

2256-
spin_lock.lock();
2317+
mutex.lock();
22572318

22582319
#ifdef DEBUG_ENABLED
22592320

2260-
if (object_slots[slot].object != p_object) {
2261-
spin_lock.unlock();
2262-
ERR_FAIL_COND(object_slots[slot].object != p_object);
2321+
if (blocks[slot.block_number][slot.block_position].object != p_object) {
2322+
mutex.unlock();
2323+
ERR_FAIL_COND(blocks[slot.block_number][slot.block_position].object != p_object);
22632324
}
22642325
{
2265-
uint64_t validator = (t >> OBJECTDB_SLOT_MAX_COUNT_BITS) & OBJECTDB_VALIDATOR_MASK;
2266-
if (object_slots[slot].validator != validator) {
2267-
spin_lock.unlock();
2268-
ERR_FAIL_COND(object_slots[slot].validator != validator);
2326+
uint64_t validator = (t >> OBJECTDB_SLOT_MAX_POSITION_BITS) & OBJECTDB_VALIDATOR_MASK;
2327+
if (blocks[slot.block_number][slot.block_position].validator != validator) {
2328+
mutex.unlock();
2329+
ERR_FAIL_COND(blocks[slot.block_number][slot.block_position].validator != validator);
22692330
}
22702331
}
22712332

22722333
#endif
22732334
//decrease slot count
2335+
if (slot_count == 0) {
2336+
block_count--;
2337+
slot_count = blocks_max_sizes[block_count];
2338+
}
22742339
slot_count--;
22752340
//set the free slot properly
2276-
object_slots[slot_count].next_free = slot;
2341+
blocks[block_count][slot_count].next_free = slot;
22772342
//invalidate, so checks against it fail
2278-
object_slots[slot].validator = 0;
2279-
object_slots[slot].is_ref_counted = false;
2280-
object_slots[slot].object = nullptr;
2343+
blocks[slot.block_number][slot.block_position].validator = 0;
2344+
blocks[slot.block_number][slot.block_position].is_ref_counted = false;
2345+
blocks[slot.block_number][slot.block_position].object = nullptr;
22812346

2282-
spin_lock.unlock();
2347+
mutex.unlock();
22832348
}
22842349

22852350
void ObjectDB::setup() {
22862351
//nothing to do now
22872352
}
22882353

22892354
void ObjectDB::cleanup() {
2290-
spin_lock.lock();
2355+
mutex.lock();
22912356

22922357
if (slot_count > 0) {
22932358
WARN_PRINT("ObjectDB instances leaked at exit (run with --verbose for details).");
@@ -2299,32 +2364,51 @@ void ObjectDB::cleanup() {
22992364
MethodBind *resource_get_path = ClassDB::get_method("Resource", "get_path");
23002365
Callable::CallError call_error;
23012366

2302-
for (uint32_t i = 0, count = slot_count; i < slot_max && count != 0; i++) {
2303-
if (object_slots[i].validator) {
2304-
Object *obj = object_slots[i].object;
2305-
2306-
String extra_info;
2307-
if (obj->is_class("Node")) {
2308-
extra_info = " - Node name: " + String(node_get_name->call(obj, nullptr, 0, call_error));
2367+
for (uint32_t i = 1; i < block_count; i++) {
2368+
for (uint32_t j = 0; j < blocks_max_sizes[i]; j++) {
2369+
if (blocks[i][j].validator) {
2370+
Object *obj = blocks[i][j].object;
2371+
2372+
String extra_info;
2373+
if (obj->is_class("Node")) {
2374+
extra_info = " - Node path: " + String(node_get_name->call(obj, nullptr, 0, call_error));
2375+
}
2376+
if (obj->is_class("Resource")) {
2377+
extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error));
2378+
}
2379+
2380+
uint64_t id = uint64_t(i) | (uint64_t(blocks[i][j].validator) << OBJECTDB_SLOT_MAX_COUNT_BITS) | (blocks[i][j].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0);
2381+
DEV_ASSERT(id == (uint64_t)obj->get_instance_id()); // We could just use the id from the object, but this check may help catching memory corruption catastrophes.
2382+
print_line("Leaked instance: " + String(obj->get_class()) + ":" + uitos(id) + extra_info);
23092383
}
2310-
if (obj->is_class("Resource")) {
2311-
extra_info = " - Resource path: " + String(resource_get_path->call(obj, nullptr, 0, call_error));
2312-
}
2313-
2314-
uint64_t id = uint64_t(i) | (uint64_t(object_slots[i].validator) << OBJECTDB_SLOT_MAX_COUNT_BITS) | (object_slots[i].is_ref_counted ? OBJECTDB_REFERENCE_BIT : 0);
2315-
DEV_ASSERT(id == (uint64_t)obj->get_instance_id()); // We could just use the id from the object, but this check may help catching memory corruption catastrophes.
2316-
print_line("Leaked instance: " + String(obj->get_class()) + ":" + uitos(id) + extra_info);
2317-
2318-
count--;
23192384
}
23202385
}
23212386
print_line("Hint: Leaked instances typically happen when nodes are removed from the scene tree (with `remove_child()`) but not freed (with `free()` or `queue_free()`).");
23222387
}
23232388
}
23242389

2325-
if (object_slots) {
2326-
memfree(object_slots);
2390+
for (uint32_t i = 1; i < block_count; i++) {
2391+
memfree(blocks[i]);
23272392
}
2328-
2329-
spin_lock.unlock();
2393+
mutex.unlock();
23302394
}
2395+
2396+
Object *ObjectDB::get_instance(ObjectID p_instance_id) {
2397+
uint64_t id = p_instance_id;
2398+
NextFree slot;
2399+
slot.position = id & OBJECTDB_SLOT_MAX_POSITION_MASK;
2400+
2401+
ERR_FAIL_COND_V(slot.block_number > block_max, nullptr); // This should never happen unless RID is corrupted.
2402+
ERR_FAIL_COND_V(slot.block_position >= slot_max, nullptr); // Same here.
2403+
2404+
if (unlikely(slot.block_number == 0)) { // Null Object.
2405+
return nullptr;
2406+
}
2407+
uint64_t validator = (id >> OBJECTDB_SLOT_MAX_POSITION_BITS) & OBJECTDB_VALIDATOR_MASK;
2408+
if (unlikely(blocks[slot.block_number][slot.block_position].validator != validator)) {
2409+
return nullptr;
2410+
}
2411+
Object *object = blocks[slot.block_number][slot.block_position].object;
2412+
2413+
return object;
2414+
}

0 commit comments

Comments
 (0)