@@ -614,7 +614,11 @@ Variant Object::_call_bind(const Variant **p_args, int p_argcount, Callable::Cal
614
614
return Variant ();
615
615
}
616
616
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 ];
618
622
619
623
return callp (method, &p_args[1 ], p_argcount - 1 , r_error);
620
624
}
@@ -635,9 +639,16 @@ Variant Object::_call_deferred_bind(const Variant **p_args, int p_argcount, Call
635
639
636
640
r_error.error = Callable::CallError::CALL_OK;
637
641
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
+ }
639
650
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 );
641
652
642
653
return Variant ();
643
654
}
@@ -2138,15 +2149,17 @@ void postinitialize_handler(Object *p_object) {
2138
2149
}
2139
2150
2140
2151
void ObjectDB::debug_objects (DebugFunc p_func) {
2141
- spin_lock .lock ();
2152
+ mutex .lock ();
2142
2153
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
+ }
2147
2160
}
2148
2161
}
2149
- spin_lock .unlock ();
2162
+ mutex .unlock ();
2150
2163
}
2151
2164
2152
2165
#ifdef TOOLS_ENABLED
@@ -2195,99 +2208,151 @@ void Object::get_argument_options(const StringName &p_function, int p_idx, List<
2195
2208
}
2196
2209
#endif
2197
2210
2198
- SpinLock ObjectDB::spin_lock ;
2211
+ BinaryMutex ObjectDB::mutex ;
2199
2212
uint32_t ObjectDB::slot_count = 0 ;
2213
+ uint32_t ObjectDB::block_count = 0 ;
2200
2214
uint32_t ObjectDB::slot_max = 0 ;
2201
- ObjectDB::ObjectSlot * ObjectDB::object_slots = nullptr ;
2215
+ uint32_t ObjectDB::block_max = 0 ;
2202
2216
uint64_t ObjectDB::validator_counter = 0 ;
2203
2217
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
+
2204
2255
int ObjectDB::get_object_count () {
2205
2256
return slot_count;
2206
2257
}
2207
2258
2208
2259
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);
2211
2268
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 ;
2220
2277
}
2221
2278
slot_max = new_slot_max;
2279
+ block_count = block_max;
2280
+ slot_count = 0 ;
2222
2281
}
2223
2282
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 ());
2228
2288
}
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 ();
2231
2291
validator_counter = (validator_counter + 1 ) & OBJECTDB_VALIDATOR_MASK;
2232
2292
if (unlikely (validator_counter == 0 )) {
2233
2293
validator_counter = 1 ;
2234
2294
}
2235
- object_slots [slot].validator = validator_counter;
2295
+ blocks [slot. block_number ][slot. block_position ].validator = validator_counter;
2236
2296
2237
2297
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 );
2240
2300
2241
2301
if (p_object->is_ref_counted ()) {
2242
2302
id |= OBJECTDB_REFERENCE_BIT;
2243
2303
}
2244
2304
2245
2305
slot_count++;
2246
2306
2247
- spin_lock .unlock ();
2307
+ mutex .unlock ();
2248
2308
2249
2309
return ObjectID (id);
2250
2310
}
2251
2311
2252
2312
void ObjectDB::remove_instance (Object *p_object) {
2253
2313
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;
2255
2316
2256
- spin_lock .lock ();
2317
+ mutex .lock ();
2257
2318
2258
2319
#ifdef DEBUG_ENABLED
2259
2320
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);
2263
2324
}
2264
2325
{
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);
2269
2330
}
2270
2331
}
2271
2332
2272
2333
#endif
2273
2334
// decrease slot count
2335
+ if (slot_count == 0 ) {
2336
+ block_count--;
2337
+ slot_count = blocks_max_sizes[block_count];
2338
+ }
2274
2339
slot_count--;
2275
2340
// set the free slot properly
2276
- object_slots [slot_count].next_free = slot;
2341
+ blocks[block_count] [slot_count].next_free = slot;
2277
2342
// 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 ;
2281
2346
2282
- spin_lock .unlock ();
2347
+ mutex .unlock ();
2283
2348
}
2284
2349
2285
2350
void ObjectDB::setup () {
2286
2351
// nothing to do now
2287
2352
}
2288
2353
2289
2354
void ObjectDB::cleanup () {
2290
- spin_lock .lock ();
2355
+ mutex .lock ();
2291
2356
2292
2357
if (slot_count > 0 ) {
2293
2358
WARN_PRINT (" ObjectDB instances leaked at exit (run with --verbose for details)." );
@@ -2299,32 +2364,51 @@ void ObjectDB::cleanup() {
2299
2364
MethodBind *resource_get_path = ClassDB::get_method (" Resource" , " get_path" );
2300
2365
Callable::CallError call_error;
2301
2366
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);
2309
2383
}
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--;
2319
2384
}
2320
2385
}
2321
2386
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()`)." );
2322
2387
}
2323
2388
}
2324
2389
2325
- if (object_slots ) {
2326
- memfree (object_slots );
2390
+ for ( uint32_t i = 1 ; i < block_count; i++ ) {
2391
+ memfree (blocks[i] );
2327
2392
}
2328
-
2329
- spin_lock.unlock ();
2393
+ mutex.unlock ();
2330
2394
}
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