summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Guyomarc'h <jean@guyomarch.bzh>2018-01-13 11:25:05 +0100
committerJean Guyomarc'h <jean@guyomarch.bzh>2018-01-13 11:25:05 +0100
commit96dc5e1ef34869e792b5f83cd38bfb92332e5a07 (patch)
tree9f5eafa845a490b91e2accc53b33c5e0f09d8332
parentaf2d961047ca03149c5342e633344570670020e0 (diff)
wip/eo: rewrite access tables
Meh. I seemed more efficient that the double lookup, but it does not seem that much of a deal-breaker.
-rw-r--r--src/lib/eo/eo.c258
-rw-r--r--src/lib/eo/eo_ptr_indirection.c183
-rw-r--r--src/lib/eo/eo_ptr_indirection.h8
-rw-r--r--src/lib/eo/eo_ptr_indirection.x12
-rw-r--r--src/lib/eo/eo_ptr_indirection2.x466
5 files changed, 662 insertions, 265 deletions
diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c
index 1298a0e1c0..1e77598bb9 100644
--- a/src/lib/eo/eo.c
+++ b/src/lib/eo/eo.c
@@ -1719,46 +1719,44 @@ err:
1719EAPI Eina_Bool 1719EAPI Eina_Bool
1720efl_isa(const Eo *eo_id, const Efl_Class *klass_id) 1720efl_isa(const Eo *eo_id, const Efl_Class *klass_id)
1721{ 1721{
1722 Efl_Id_Domain domain;
1723 Eo_Id_Data *data;
1724 Eo_Id_Table_Data *tdata;
1725 Eina_Bool isa = EINA_FALSE;
1726 1722
1727 if (EINA_UNLIKELY(!eo_id)) return EINA_FALSE; 1723 if (EINA_UNLIKELY(!eo_id)) return EINA_FALSE;
1728 domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
1729 data = _eo_table_data_get();
1730 tdata = _eo_table_data_table_get(data, domain);
1731 if (EINA_UNLIKELY(!tdata)) goto err;
1732 1724
1725 const Efl_Id_Domain domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
1726 Eo_Id_Data *const data = _eo_id_data_get();
1727 Eo_Id_Table *const table = _eo_id_data_table_get(data, domain);
1728 if (EINA_UNLIKELY(!table)) goto err;
1729
1730 Eina_Bool isa = EINA_FALSE;
1733 if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED)) 1731 if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED))
1734 { 1732 {
1735 if ((tdata->cache.isa_id == eo_id) && 1733 if ((table->cache.isa_id == eo_id) &&
1736 (tdata->cache.klass == klass_id)) 1734 (table->cache.klass == klass_id))
1737 { 1735 {
1738 isa = tdata->cache.isa; 1736 isa = table->cache.isa;
1739 return isa; 1737 return isa;
1740 } 1738 }
1741 1739
1742 EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj); 1740 EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj);
1743 EO_CLASS_POINTER_GOTO(klass_id, klass, err_class); 1741 EO_CLASS_POINTER_GOTO(klass_id, klass, err_class);
1744 const op_type_funcs *func = _vtable_func_get 1742 const op_type_funcs *const func = _vtable_func_get
1745 (EO_VTABLE(obj), klass->base_id + klass->ops_count); 1743 (EO_VTABLE(obj), klass->base_id + klass->ops_count);
1746 1744
1747 // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it. 1745 // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it.
1748 tdata->cache.isa_id = eo_id; 1746 table->cache.isa_id = eo_id;
1749 tdata->cache.klass = klass_id; 1747 table->cache.klass = klass_id;
1750 // Currently implemented by reusing the LAST op id. Just marking it with 1748 // Currently implemented by reusing the LAST op id. Just marking it with
1751 // _eo_class_isa_func. 1749 // _eo_class_isa_func.
1752 isa = tdata->cache.isa = (func && (func->func == _eo_class_isa_func)); 1750 isa = table->cache.isa = (func && (func->func == _eo_class_isa_func));
1753 } 1751 }
1754 else 1752 else
1755 { 1753 {
1756 eina_lock_take(&(_eo_table_data_shared_data->obj_lock)); 1754 eina_lock_take(&(_eo_table_data_shared_data->obj_lock));
1757 1755
1758 if ((tdata->cache.isa_id == eo_id) && 1756 if ((table->cache.isa_id == eo_id) &&
1759 (tdata->cache.klass == klass_id)) 1757 (table->cache.klass == klass_id))
1760 { 1758 {
1761 isa = tdata->cache.isa; 1759 isa = table->cache.isa;
1762 // since this is the cache we hope this gets a lot of hits and 1760 // since this is the cache we hope this gets a lot of hits and
1763 // thus lets assume the hit is the mot important thing thus 1761 // thus lets assume the hit is the mot important thing thus
1764 // put the lock release and return here inline in the l1 1762 // put the lock release and return here inline in the l1
@@ -1769,15 +1767,15 @@ efl_isa(const Eo *eo_id, const Efl_Class *klass_id)
1769 1767
1770 EO_OBJ_POINTER_GOTO(eo_id, obj, err_shared_obj); 1768 EO_OBJ_POINTER_GOTO(eo_id, obj, err_shared_obj);
1771 EO_CLASS_POINTER_GOTO(klass_id, klass, err_shared_class); 1769 EO_CLASS_POINTER_GOTO(klass_id, klass, err_shared_class);
1772 const op_type_funcs *func = _vtable_func_get 1770 const op_type_funcs *const func = _vtable_func_get
1773 (EO_VTABLE(obj), klass->base_id + klass->ops_count); 1771 (EO_VTABLE(obj), klass->base_id + klass->ops_count);
1774 1772
1775 // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it. 1773 // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it.
1776 tdata->cache.isa_id = eo_id; 1774 table->cache.isa_id = eo_id;
1777 tdata->cache.klass = klass_id; 1775 table->cache.klass = klass_id;
1778 // Currently implemented by reusing the LAST op id. Just marking it with 1776 // Currently implemented by reusing the LAST op id. Just marking it with
1779 // _eo_class_isa_func. 1777 // _eo_class_isa_func.
1780 isa = tdata->cache.isa = (func && (func->func == _eo_class_isa_func)); 1778 isa = table->cache.isa = (func && (func->func == _eo_class_isa_func));
1781 EO_OBJ_DONE(eo_id); 1779 EO_OBJ_DONE(eo_id);
1782 eina_lock_release(&(_eo_table_data_shared_data->obj_lock)); 1780 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
1783 } 1781 }
@@ -2177,12 +2175,12 @@ efl_data_xunref_internal(const Eo *obj_id, void *data, const Eo *ref_obj_id)
2177 EO_OBJ_DONE(obj_id); 2175 EO_OBJ_DONE(obj_id);
2178} 2176}
2179 2177
2180static void 2178//static void
2181_eo_table_del_cb(void *in) 2179//_eo_table_del_cb(void *in)
2182{ 2180//{
2183 Eo_Id_Data *data = in; 2181// Eo_Id_Data *data = in;
2184 _eo_free_ids_tables(data); 2182// _eo_free_ids_tables(data);
2185} 2183//}
2186 2184
2187/* FIXME: Support other domains and tables, at the moment only the main 2185/* FIXME: Support other domains and tables, at the moment only the main
2188 * domain and table. 2186 * domain and table.
@@ -2244,7 +2242,7 @@ efl_object_init(void)
2244 _ops_storage = eina_hash_string_superfast_new(NULL); 2242 _ops_storage = eina_hash_string_superfast_new(NULL);
2245#endif 2243#endif
2246 2244
2247 _eo_table_data_shared = _eo_table_data_new(EFL_ID_DOMAIN_SHARED); 2245 _eo_table_data_shared = _eo_id_data_new(EFL_ID_DOMAIN_SHARED);
2248 if (!_eo_table_data_shared) 2246 if (!_eo_table_data_shared)
2249 { 2247 {
2250 ERR("Could not allocate shared table data"); 2248 ERR("Could not allocate shared table data");
@@ -2253,20 +2251,13 @@ efl_object_init(void)
2253 _eo_table_data_shared_data = _eo_table_data_shared->tables[EFL_ID_DOMAIN_SHARED]; 2251 _eo_table_data_shared_data = _eo_table_data_shared->tables[EFL_ID_DOMAIN_SHARED];
2254 2252
2255 // specially force eoid data to be creanted so we can switch it to domain 0 2253 // specially force eoid data to be creanted so we can switch it to domain 0
2256 Eo_Id_Data *data = _eo_table_data_new(EFL_ID_DOMAIN_MAIN); 2254 _eo_id_data = _eo_id_data_new(EFL_ID_DOMAIN_MAIN);
2257 _eo_gdb_main_domain = data; 2255 _eo_gdb_main_domain = _eo_id_data;
2258 if (!data) 2256 if (EINA_UNLIKELY(!_eo_id_data))
2259 { 2257 {
2260 ERR("Could not allocate main table data"); 2258 ERR("Could not allocate main table data");
2261 return EINA_FALSE; 2259 return EINA_FALSE;
2262 } 2260 }
2263 if (!eina_tls_cb_new(&_eo_table_data, _eo_table_del_cb))
2264 {
2265 ERR("Could not allocate TLS for eo domain data");
2266 _eo_table_del_cb(data);
2267 return EINA_FALSE;
2268 }
2269 eina_tls_set(_eo_table_data, data);
2270 _efl_object_main_thread = eina_thread_self(); 2261 _efl_object_main_thread = eina_thread_self();
2271 2262
2272#ifdef EO_DEBUG 2263#ifdef EO_DEBUG
@@ -2326,11 +2317,10 @@ efl_object_shutdown(void)
2326 eina_spinlock_free(&_ops_storage_lock); 2317 eina_spinlock_free(&_ops_storage_lock);
2327 eina_lock_free(&_efl_class_creation_lock); 2318 eina_lock_free(&_efl_class_creation_lock);
2328 2319
2329 _eo_free_ids_tables(_eo_table_data_get()); 2320// _eo_free_ids_tables(_eo_id_data_get());
2330 eina_tls_free(_eo_table_data);
2331 if (_eo_table_data_shared) 2321 if (_eo_table_data_shared)
2332 { 2322 {
2333 _eo_free_ids_tables(_eo_table_data_shared); 2323 //_eo_free_ids_tables(_eo_table_data_shared);
2334 _eo_table_data_shared = NULL; 2324 _eo_table_data_shared = NULL;
2335 _eo_table_data_shared_data = NULL; 2325 _eo_table_data_shared_data = NULL;
2336 } 2326 }
@@ -2354,21 +2344,21 @@ efl_object_shutdown(void)
2354EAPI Efl_Id_Domain 2344EAPI Efl_Id_Domain
2355efl_domain_get(void) 2345efl_domain_get(void)
2356{ 2346{
2357 Eo_Id_Data *data = _eo_table_data_get(); 2347 Eo_Id_Data *data = _eo_id_data_get();
2358 return data->local_domain; 2348 return data->local_domain;
2359} 2349}
2360 2350
2361EAPI Efl_Id_Domain 2351EAPI Efl_Id_Domain
2362efl_domain_current_get(void) 2352efl_domain_current_get(void)
2363{ 2353{
2364 Eo_Id_Data *data = _eo_table_data_get(); 2354 Eo_Id_Data *data = _eo_id_data_get();
2365 return data->domain_stack[data->stack_top]; 2355 return data->domain_stack[data->stack_top];
2366} 2356}
2367 2357
2368EAPI Eina_Bool 2358EAPI Eina_Bool
2369efl_domain_switch(Efl_Id_Domain domain) 2359efl_domain_switch(Efl_Id_Domain domain)
2370{ 2360{
2371 Eo_Id_Data *data = _eo_table_data_get(); 2361 Eo_Id_Data *data = _eo_id_data_get();
2372 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD) || 2362 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD) ||
2373 (domain == EFL_ID_DOMAIN_SHARED)) 2363 (domain == EFL_ID_DOMAIN_SHARED))
2374 { 2364 {
@@ -2378,12 +2368,12 @@ efl_domain_switch(Efl_Id_Domain domain)
2378 if (data) 2368 if (data)
2379 { 2369 {
2380 if (data->local_domain == domain) return EINA_TRUE; 2370 if (data->local_domain == domain) return EINA_TRUE;
2381 _eo_free_ids_tables(data); 2371 //_eo_free_ids_tables(data);
2382 } 2372 }
2383 data = _eo_table_data_new(domain); 2373 data = _eo_id_data_new(domain);
2384 data->local_domain = domain; 2374 data->local_domain = domain;
2385 data->domain_stack[data->stack_top] = domain; 2375 data->domain_stack[data->stack_top] = domain;
2386 eina_tls_set(_eo_table_data, data); 2376 _eo_id_data = data;
2387 return EINA_TRUE; 2377 return EINA_TRUE;
2388} 2378}
2389 2379
@@ -2410,21 +2400,21 @@ _efl_domain_pop(Eo_Id_Data *data)
2410EAPI Eina_Bool 2400EAPI Eina_Bool
2411efl_domain_current_push(Efl_Id_Domain domain) 2401efl_domain_current_push(Efl_Id_Domain domain)
2412{ 2402{
2413 Eo_Id_Data *data = _eo_table_data_get(); 2403 Eo_Id_Data *data = _eo_id_data_get();
2414 return _efl_domain_push(data, domain); 2404 return _efl_domain_push(data, domain);
2415} 2405}
2416 2406
2417EAPI void 2407EAPI void
2418efl_domain_current_pop(void) 2408efl_domain_current_pop(void)
2419{ 2409{
2420 Eo_Id_Data *data = _eo_table_data_get(); 2410 Eo_Id_Data *data = _eo_id_data_get();
2421 _efl_domain_pop(data); 2411 _efl_domain_pop(data);
2422} 2412}
2423 2413
2424EAPI Eina_Bool 2414EAPI Eina_Bool
2425efl_domain_current_set(Efl_Id_Domain domain) 2415efl_domain_current_set(Efl_Id_Domain domain)
2426{ 2416{
2427 Eo_Id_Data *data = _eo_table_data_get(); 2417 Eo_Id_Data *data = _eo_id_data_get();
2428 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD)) 2418 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD))
2429 { 2419 {
2430 ERR("Invalid domain %i being set", domain); 2420 ERR("Invalid domain %i being set", domain);
@@ -2437,14 +2427,14 @@ efl_domain_current_set(Efl_Id_Domain domain)
2437EAPI Efl_Domain_Data * 2427EAPI Efl_Domain_Data *
2438efl_domain_data_get(void) 2428efl_domain_data_get(void)
2439{ 2429{
2440 Eo_Id_Data *data = _eo_table_data_get(); 2430 Eo_Id_Data *data = _eo_id_data_get();
2441 return (Efl_Domain_Data *)data; 2431 return (Efl_Domain_Data *)data;
2442} 2432}
2443 2433
2444EAPI Efl_Id_Domain 2434EAPI Efl_Id_Domain
2445efl_domain_data_adopt(Efl_Domain_Data *data_in) 2435efl_domain_data_adopt(Efl_Domain_Data *data_in)
2446{ 2436{
2447 Eo_Id_Data *data = _eo_table_data_get(); 2437 Eo_Id_Data *data = _eo_id_data_get();
2448 Eo_Id_Data *data_foreign = (Eo_Id_Data *)data_in; 2438 Eo_Id_Data *data_foreign = (Eo_Id_Data *)data_in;
2449 2439
2450 if (!data_foreign) 2440 if (!data_foreign)
@@ -2472,7 +2462,7 @@ efl_domain_data_adopt(Efl_Domain_Data *data_in)
2472EAPI Eina_Bool 2462EAPI Eina_Bool
2473efl_domain_data_return(Efl_Id_Domain domain) 2463efl_domain_data_return(Efl_Id_Domain domain)
2474{ 2464{
2475 Eo_Id_Data *data = _eo_table_data_get(); 2465 Eo_Id_Data *data = _eo_id_data_get();
2476 2466
2477 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD)) 2467 if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD))
2478 { 2468 {
@@ -3290,86 +3280,86 @@ eo_classes_iterator_new(void)
3290 return (Eina_Iterator *)it; 3280 return (Eina_Iterator *)it;
3291} 3281}
3292 3282
3293typedef struct 3283///typedef struct
3294{ 3284///{
3295 Eina_Iterator iterator; 3285/// Eina_Iterator iterator;
3296 Eo_Id_Table_Data *tdata; 3286/// Eo_Id_Table_Data *tdata;
3297 Table_Index mid_table_id; 3287/// Table_Index mid_table_id;
3298 Table_Index table_id; 3288/// Table_Index table_id;
3299 Table_Index entry_id; 3289/// Table_Index entry_id;
3300} _Eo_Objects_Iterator; 3290///} _Eo_Objects_Iterator;
3301 3291///
3302static Eina_Bool 3292///static Eina_Bool
3303_eo_objects_iterator_next(Eina_Iterator *it, void **data) 3293///_eo_objects_iterator_next(Eina_Iterator *it, void **data)
3304{ 3294///{
3305 Table_Index mid_table_id, table_id, entry_id; 3295/// Table_Index mid_table_id, table_id, entry_id;
3306 Eo_Id_Table_Data *tdata; 3296/// Eo_Id_Table_Data *tdata;
3307 _Eo_Objects_Iterator *eo_it = (_Eo_Objects_Iterator *)it; 3297/// _Eo_Objects_Iterator *eo_it = (_Eo_Objects_Iterator *)it;
3308 if (!eo_it->tdata) return EINA_FALSE; 3298/// if (!eo_it->tdata) return EINA_FALSE;
3309 3299///
3310 tdata = eo_it->tdata; 3300/// tdata = eo_it->tdata;
3311 mid_table_id = eo_it->mid_table_id; 3301/// mid_table_id = eo_it->mid_table_id;
3312 table_id = eo_it->table_id; 3302/// table_id = eo_it->table_id;
3313 entry_id = eo_it->entry_id; 3303/// entry_id = eo_it->entry_id;
3314 while (mid_table_id < MAX_MID_TABLE_ID) 3304/// while (mid_table_id < MAX_MID_TABLE_ID)
3315 { 3305/// {
3316 if (tdata->eo_ids_tables[mid_table_id]) 3306/// if (tdata->eo_ids_tables[mid_table_id])
3317 { 3307/// {
3318 while (table_id < MAX_TABLE_ID) 3308/// while (table_id < MAX_TABLE_ID)
3319 { 3309/// {
3320 if (TABLE_FROM_IDS) 3310/// if (TABLE_FROM_IDS)
3321 { 3311/// {
3322 while (entry_id < MAX_ENTRY_ID) 3312/// while (entry_id < MAX_ENTRY_ID)
3323 { 3313/// {
3324 _Eo_Id_Entry *entry = &(TABLE_FROM_IDS->entries[entry_id]); 3314/// _Eo_Id_Entry *entry = &(TABLE_FROM_IDS->entries[entry_id]);
3325 if (entry->active) 3315/// if (entry->generation != 0)
3326 { 3316/// {
3327 Eo *obj = _eo_header_id_get((Eo_Header *) entry->ptr); 3317/// Eo *obj = _eo_header_id_get((Eo_Header *) entry->ptr);
3328 *data = obj; 3318/// *data = obj;
3329 eo_it->mid_table_id = mid_table_id; 3319/// eo_it->mid_table_id = mid_table_id;
3330 eo_it->table_id = table_id; 3320/// eo_it->table_id = table_id;
3331 eo_it->entry_id = entry_id + 1; 3321/// eo_it->entry_id = entry_id + 1;
3332 return EINA_TRUE; 3322/// return EINA_TRUE;
3333 } 3323/// }
3334 entry_id++; 3324/// entry_id++;
3335 } 3325/// }
3336 entry_id = 0; 3326/// entry_id = 0;
3337 } 3327/// }
3338 table_id++; 3328/// table_id++;
3339 } 3329/// }
3340 table_id = 0; 3330/// table_id = 0;
3341 } 3331/// }
3342 mid_table_id++; 3332/// mid_table_id++;
3343 } 3333/// }
3344 return EINA_FALSE; 3334/// return EINA_FALSE;
3345} 3335///}
3346 3336///
3347static void 3337///static void
3348_eo_objects_iterator_free(Eina_Iterator *it) 3338///_eo_objects_iterator_free(Eina_Iterator *it)
3349{ 3339///{
3350 EINA_MAGIC_SET(it, EINA_MAGIC_NONE); 3340/// EINA_MAGIC_SET(it, EINA_MAGIC_NONE);
3351 free(it); 3341/// free(it);
3352} 3342///}
3353 3343///
3354EAPI Eina_Iterator * 3344///EAPI Eina_Iterator *
3355eo_objects_iterator_new(void) 3345///eo_objects_iterator_new(void)
3356{ 3346///{
3357 _Eo_Objects_Iterator *it; 3347/// _Eo_Objects_Iterator *it;
3358 Eo_Id_Table_Data *tdata = _eo_table_data_table_get(_eo_table_data_get(), EFL_ID_DOMAIN_MAIN); 3348/// Eo_Id_Table_Data *tdata = _eo_id_data_table_get(_eo_id_data_get(), EFL_ID_DOMAIN_MAIN);
3359 3349///
3360 if (!tdata) return NULL; 3350/// if (!tdata) return NULL;
3361 3351///
3362 it = calloc(1, sizeof (*it)); 3352/// it = calloc(1, sizeof (*it));
3363 if (!it) return NULL; 3353/// if (!it) return NULL;
3364 3354///
3365 it->tdata = tdata; 3355/// it->tdata = tdata;
3366 it->iterator.version = EINA_ITERATOR_VERSION; 3356/// it->iterator.version = EINA_ITERATOR_VERSION;
3367 it->iterator.next = _eo_objects_iterator_next; 3357/// it->iterator.next = _eo_objects_iterator_next;
3368 it->iterator.free = _eo_objects_iterator_free; 3358/// it->iterator.free = _eo_objects_iterator_free;
3369 EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); 3359/// EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
3370 3360///
3371 return (Eina_Iterator *)it; 3361/// return (Eina_Iterator *)it;
3372} 3362///}
3373 3363
3374static Eina_Bool 3364static Eina_Bool
3375_eo_value_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem) 3365_eo_value_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem)
diff --git a/src/lib/eo/eo_ptr_indirection.c b/src/lib/eo/eo_ptr_indirection.c
index d7fd68520a..4b3adbf1a5 100644
--- a/src/lib/eo/eo_ptr_indirection.c
+++ b/src/lib/eo/eo_ptr_indirection.c
@@ -8,12 +8,14 @@ extern Eina_Thread _efl_object_main_thread;
8 8
9////////////////////////////////////////////////////////////////////////// 9//////////////////////////////////////////////////////////////////////////
10 10
11Eina_TLS _eo_table_data; 11Eo_Id_Data *_eo_table_data_shared;
12Eo_Id_Data *_eo_table_data_shared = NULL; 12Eo_Id_Table *_eo_table_data_shared_data;
13Eo_Id_Table_Data *_eo_table_data_shared_data = NULL;
14 13
15Eo_Id_Data _eo_main_table_data; 14
16Eo_Id_Table_Data _eo_table_main_table_data; 15Eo_Id_Data _eo_main_id_data;
16Eo_Id_Table _eo_main_id_table;
17
18Eo_Id_Data *_eo_id_data;
17 19
18////////////////////////////////////////////////////////////////////////// 20//////////////////////////////////////////////////////////////////////////
19 21
@@ -74,7 +76,7 @@ _eo_obj_pointer_invalid(const Eo_Id obj_id,
74 (data->tables[2]) ? "2" : " ", 76 (data->tables[2]) ? "2" : " ",
75 (data->tables[3]) ? "3" : " ", 77 (data->tables[3]) ? "3" : " ",
76 (unsigned long)(obj_id & MASK_GENERATIONS), 78 (unsigned long)(obj_id & MASK_GENERATIONS),
77 (unsigned long)(obj_id >> SHIFT_ENTRY_ID) & (MAX_ENTRY_ID | MAX_TABLE_ID | MAX_MID_TABLE_ID), 79 (unsigned long)((obj_id >> SHIFT_ENTRY_ID)) & MASK_ENTRY_ID,
78 (int)(obj_id >> REF_TAG_SHIFT) & 0x1); 80 (int)(obj_id >> REF_TAG_SHIFT) & 0x1);
79 _eo_log_obj_report(obj_id, EINA_LOG_LEVEL_ERR, func_name, file, line); 81 _eo_log_obj_report(obj_id, EINA_LOG_LEVEL_ERR, func_name, file, line);
80} 82}
@@ -98,48 +100,37 @@ _eo_obj_pointer_get(const Eo_Id obj_id, const char *restrict func_name, const ch
98 100
99do_domain_main: EINA_HOT 101do_domain_main: EINA_HOT
100 { 102 {
101 __builtin_prefetch(&_eo_table_main_table_data, 0, 3); 103// __builtin_prefetch(&_eo_main_id_table, 0, 3);
102 if (obj_id == _eo_table_main_table_data.cache.id) 104 if (obj_id == _eo_main_id_table.cache.id)
103 return _eo_table_main_table_data.cache.object; 105 return _eo_main_id_table.cache.object;
104 106
105 /* XXX This could definitely be done in one go with vectorization */ 107 /* XXX This could definitely be done in one go with vectorization */
106 const unsigned int mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; 108 const size_t entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
107 const unsigned int table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID; 109 const unsigned int generation = obj_id & MASK_GENERATIONS;
108 const unsigned int entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
109 const Generation_Counter generation = obj_id & MASK_GENERATIONS;
110 110
111 // get tag bit to check later down below - pipelining 111 // get tag bit to check later down below - pipelining
112 const Eo_Id tag_bit = (obj_id) & MASK_OBJ_TAG; 112 const Eo_Id tag_bit = (obj_id) & MASK_OBJ_TAG;
113 if (EINA_UNLIKELY(!tag_bit)) goto main_err; 113 if (EINA_UNLIKELY(!tag_bit ||
114 (entry_id >= _eo_main_id_table.count)))
115 goto main_err;
114 116
115 __builtin_prefetch(&(_eo_table_main_table_data.eo_ids_tables[mid_table_id]), 0, 3);
116 117
117 // Check the validity of the entry 118 register const Eo_Id_Entry *const entry = &(_eo_main_id_table.entries[entry_id]);
118 if (EINA_LIKELY(_eo_table_main_table_data.eo_ids_tables[mid_table_id] != NULL)) 119// __builtin_prefetch(entry, 0, 0);
120 if (EINA_LIKELY(entry->data.generation == generation))
119 { 121 {
120 register const _Eo_Ids_Table *const tab = 122 // Cache the result of that lookup
121 _eo_table_main_table_data.eo_ids_tables[mid_table_id][table_id]; 123 _eo_main_id_table.cache.object = entry->data.ptr;
122 124 _eo_main_id_table.cache.id = obj_id;
123 if (EINA_LIKELY(tab != NULL)) 125 return _eo_main_id_table.cache.object;
124 {
125 register const _Eo_Id_Entry *const entry = &(tab->entries[entry_id]);
126 if (EINA_LIKELY(entry->active && (entry->generation == generation)))
127 {
128 // Cache the result of that lookup
129 _eo_table_main_table_data.cache.object = entry->ptr;
130 _eo_table_main_table_data.cache.id = obj_id;
131 return _eo_table_main_table_data.cache.object;
132 }
133 }
134 } 126 }
135 127
136
137 goto main_err; 128 goto main_err;
138 } 129 }
139 130
140 131
141main_err: EINA_COLD 132main_err: EINA_COLD
142 _eo_obj_pointer_invalid(obj_id, &_eo_main_table_data, domain, func_name, file, line); 133 _eo_obj_pointer_invalid(obj_id, &_eo_main_id_data, domain, func_name, file, line);
143 return NULL; 134 return NULL;
144 135
145 136
@@ -147,55 +138,30 @@ main_err: EINA_COLD
147do_domain_thread: EINA_COLD 138do_domain_thread: EINA_COLD
148do_domain_other: EINA_COLD 139do_domain_other: EINA_COLD
149 { 140 {
150 _Eo_Id_Entry *entry; 141 Eo_Id_Data *const data = _eo_id_data_get();
151 Generation_Counter generation; 142 Eo_Id_Table *const table = _eo_id_data_table_get(data, domain);
152 unsigned int mid_table_id, table_id, entry_id; 143 if (EINA_UNLIKELY(!table)) goto err;
153 Eo_Id tag_bit;
154 Eo_Id_Data *data;
155 Eo_Id_Table_Data *tdata;
156
157
158 // NULL objects will just be sensibly ignored. not worth complaining
159 // every single time.
160
161 data = _eo_table_data_get();
162 EINA_PREFETCH(&(data->tables[0]));
163 tdata = _eo_table_data_table_get(data, domain);
164 EINA_PREFETCH(&(tdata->cache.id));
165 if (EINA_UNLIKELY(!tdata)) goto err;
166 144
167 145
168 if (obj_id == tdata->cache.id) 146 if (obj_id == table->cache.id)
169 return tdata->cache.object; 147 return table->cache.object;
170 148
171 mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; 149 const size_t entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
172 EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id])); 150 const unsigned int generation = obj_id & MASK_GENERATIONS;
173 table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID;
174 entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
175 generation = obj_id & MASK_GENERATIONS;
176 151
177 // get tag bit to check later down below - pipelining 152 // get tag bit to check later down below - pipelining
178 tag_bit = (obj_id) & MASK_OBJ_TAG; 153 const Eo_Id tag_bit = (obj_id) & MASK_OBJ_TAG;
179 if (EINA_UNLIKELY(!obj_id)) goto err_null; 154 if (EINA_UNLIKELY(!tag_bit ||
180 else if (EINA_UNLIKELY(!tag_bit)) goto err; 155 (entry_id >= table->count))) goto err;
181 156
182 // Check the validity of the entry 157 register const Eo_Id_Entry *const entry = &(table->entries[entry_id]);
183 if (tdata->eo_ids_tables[mid_table_id]) 158 if (EINA_LIKELY(entry->data.generation == generation))
184 { 159 {
185 _Eo_Ids_Table *tab = TABLE_FROM_IDS; 160 // Cache the result of that lookup
186 161 table->cache.object = entry->data.ptr;
187 if (tab) 162 table->cache.id = obj_id;
188 { 163 return entry->data.ptr;
189 entry = &(tab->entries[entry_id]); 164 }
190 if (entry->active && (entry->generation == generation))
191 {
192 // Cache the result of that lookup
193 tdata->cache.object = entry->ptr;
194 tdata->cache.id = obj_id;
195 return entry->ptr;
196 }
197 }
198 }
199 goto err; 165 goto err;
200 166
201err_null: EINA_COLD 167err_null: EINA_COLD
@@ -207,57 +173,34 @@ err: EINA_COLD
207 173
208do_domain_shared: EINA_COLD 174do_domain_shared: EINA_COLD
209 { 175 {
210 _Eo_Id_Entry *entry; 176 Eo_Id_Data *const data = _eo_table_data_shared;
211 Generation_Counter generation; 177 Eo_Id_Table *const table = _eo_table_data_shared_data;
212 unsigned int mid_table_id, table_id, entry_id; 178
213 Eo_Id tag_bit; 179 eina_lock_take(&(table->obj_lock));
214 Eo_Id_Data *data; 180 if (EINA_LIKELY(obj_id == table->cache.id))
215 Eo_Id_Table_Data *tdata;
216
217 data = _eo_table_data_get();
218 EINA_PREFETCH(&(data->tables[0]));
219 tdata = _eo_table_data_table_get(data, domain);
220 EINA_PREFETCH(&(tdata->cache.id));
221 if (EINA_UNLIKELY(!tdata)) goto err_shared_err;
222
223
224 eina_lock_take(&(_eo_table_data_shared_data->obj_lock));
225 if (EINA_LIKELY(obj_id == tdata->cache.id))
226 // yes we return keeping the lock locked. thats why 181 // yes we return keeping the lock locked. thats why
227 // you must call _eo_obj_pointer_done() wrapped 182 // you must call _eo_obj_pointer_done() wrapped
228 // by EO_OBJ_DONE() to release 183 // by EO_OBJ_DONE() to release
229 return tdata->cache.object; 184 return table->cache.object;
230 185
231 mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; 186 const size_t entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
232 EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id])); 187 const unsigned int generation = obj_id & MASK_GENERATIONS;
233 table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID;
234 entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID;
235 generation = obj_id & MASK_GENERATIONS;
236 188
237 // get tag bit to check later down below - pipelining 189 // get tag bit to check later down below - pipelining
238 tag_bit = (obj_id) & MASK_OBJ_TAG; 190 const Eo_Id tag_bit = (obj_id) & MASK_OBJ_TAG;
239 if (!obj_id) goto err_shared_null; 191 if (EINA_UNLIKELY((!tag_bit ||
240 else if (!tag_bit) goto err_shared; 192 entry_id >= table->count))) goto err_shared;
241 193
242 // Check the validity of the entry 194 Eo_Id_Entry *const entry = &(table->entries[entry_id]);
243 if (tdata->eo_ids_tables[mid_table_id]) 195 if (EINA_LIKELY(entry->data.generation == generation))
244 { 196 {
245 _Eo_Ids_Table *tab = TABLE_FROM_IDS; 197 // Cache the result of that lookup
246 198 table->cache.object = entry->data.ptr;
247 if (tab) 199 table->cache.id = obj_id;
248 { 200 // yes we return keeping the lock locked. thats why
249 entry = &(tab->entries[entry_id]); 201 // you must call _eo_obj_pointer_done() wrapped
250 if (entry->active && (entry->generation == generation)) 202 // by EO_OBJ_DONE() to release
251 { 203 return entry->data.ptr;
252 // Cache the result of that lookup
253 tdata->cache.object = entry->ptr;
254 tdata->cache.id = obj_id;
255 // yes we return keeping the lock locked. thats why
256 // you must call _eo_obj_pointer_done() wrapped
257 // by EO_OBJ_DONE() to release
258 return entry->ptr;
259 }
260 }
261 } 204 }
262 goto err_shared; 205 goto err_shared;
263 206
diff --git a/src/lib/eo/eo_ptr_indirection.h b/src/lib/eo/eo_ptr_indirection.h
index 9cde5ba0c2..d3b175975f 100644
--- a/src/lib/eo/eo_ptr_indirection.h
+++ b/src/lib/eo/eo_ptr_indirection.h
@@ -139,12 +139,12 @@ void _eo_pointer_error(const Eo *obj_id, const char *func_name, const char *file
139static inline void _eo_print(Eo_Id_Table_Data *tdata); 139static inline void _eo_print(Eo_Id_Table_Data *tdata);
140#endif 140#endif
141 141
142extern Eina_TLS _eo_table_data; 142//extern Eina_TLS _eo_table_data;
143 143
144#include "eo_ptr_indirection.x" 144#include "eo_ptr_indirection2.x"
145 145
146extern Eo_Id_Data *_eo_table_data_shared; 146//extern Eo_Id_Data *_eo_table_data_shared;
147extern Eo_Id_Table_Data *_eo_table_data_shared_data; 147//extern Eo_Id_Table_Data *_eo_table_data_shared_data;
148 148
149#endif 149#endif
150 150
diff --git a/src/lib/eo/eo_ptr_indirection.x b/src/lib/eo/eo_ptr_indirection.x
index b8724b1148..495c489f52 100644
--- a/src/lib/eo/eo_ptr_indirection.x
+++ b/src/lib/eo/eo_ptr_indirection.x
@@ -546,7 +546,6 @@ _eo_id_allocate(const _Eo_Object *obj, const Eo *parent_id)
546 if (tdata->generation >= MAX_GENERATIONS) tdata->generation = 1; 546 if (tdata->generation >= MAX_GENERATIONS) tdata->generation = 1;
547 /* Fill the entry and return it's Eo Id */ 547 /* Fill the entry and return it's Eo Id */
548 entry->ptr = (_Eo_Object *)obj; 548 entry->ptr = (_Eo_Object *)obj;
549 entry->active = 1;
550 entry->generation = tdata->generation; 549 entry->generation = tdata->generation;
551 PROTECT(tdata->current_table); 550 PROTECT(tdata->current_table);
552 id = EO_COMPOSE_FINAL_ID(tdata->current_table->partial_id, 551 id = EO_COMPOSE_FINAL_ID(tdata->current_table->partial_id,
@@ -574,7 +573,6 @@ _eo_id_allocate(const _Eo_Object *obj, const Eo *parent_id)
574 if (tdata->generation == MAX_GENERATIONS) tdata->generation = 1; 573 if (tdata->generation == MAX_GENERATIONS) tdata->generation = 1;
575 /* Fill the entry and return it's Eo Id */ 574 /* Fill the entry and return it's Eo Id */
576 entry->ptr = (_Eo_Object *)obj; 575 entry->ptr = (_Eo_Object *)obj;
577 entry->active = 1;
578 entry->generation = tdata->generation; 576 entry->generation = tdata->generation;
579 PROTECT(tdata->current_table); 577 PROTECT(tdata->current_table);
580 id = EO_COMPOSE_FINAL_ID(tdata->current_table->partial_id, 578 id = EO_COMPOSE_FINAL_ID(tdata->current_table->partial_id,
@@ -611,12 +609,12 @@ _eo_id_release(const Eo_Id obj_id)
611 if (tdata->eo_ids_tables[mid_table_id] && (table = TABLE_FROM_IDS)) 609 if (tdata->eo_ids_tables[mid_table_id] && (table = TABLE_FROM_IDS))
612 { 610 {
613 entry = &(table->entries[entry_id]); 611 entry = &(table->entries[entry_id]);
614 if (entry && entry->active && (entry->generation == generation)) 612 if (entry->generation == generation)
615 { 613 {
616 UNPROTECT(table); 614 UNPROTECT(table);
617 table->free_entries++; 615 table->free_entries++;
618 // Disable the entry 616 // Disable the entry
619 entry->active = 0; 617 entry->generation = 0;
620 entry->next_in_fifo = -1; 618 entry->next_in_fifo = -1;
621 // Push the entry into the fifo 619 // Push the entry into the fifo
622 if (table->fifo_tail == -1) 620 if (table->fifo_tail == -1)
@@ -661,12 +659,12 @@ _eo_id_release(const Eo_Id obj_id)
661 if (tdata->eo_ids_tables[mid_table_id] && (table = TABLE_FROM_IDS)) 659 if (tdata->eo_ids_tables[mid_table_id] && (table = TABLE_FROM_IDS))
662 { 660 {
663 entry = &(table->entries[entry_id]); 661 entry = &(table->entries[entry_id]);
664 if (entry && entry->active && (entry->generation == generation)) 662 if (entry->generation == generation)
665 { 663 {
666 UNPROTECT(table); 664 UNPROTECT(table);
667 table->free_entries++; 665 table->free_entries++;
668 // Disable the entry 666 // Disable the entry
669 entry->active = 0; 667 entry->generation = 0;
670 entry->next_in_fifo = -1; 668 entry->next_in_fifo = -1;
671 // Push the entry into the fifo 669 // Push the entry into the fifo
672 if (table->fifo_tail == -1) 670 if (table->fifo_tail == -1)
@@ -759,7 +757,7 @@ _eo_print(Eo_Id_Table_Data *tdata)
759 for (Table_Index entry_id = 0; entry_id < MAX_ENTRY_ID; entry_id++) 757 for (Table_Index entry_id = 0; entry_id < MAX_ENTRY_ID; entry_id++)
760 { 758 {
761 entry = &(TABLE_FROM_IDS->entries[entry_id]); 759 entry = &(TABLE_FROM_IDS->entries[entry_id]);
762 if (entry->active) 760 if (entry->generation != 0)
763 { 761 {
764 printf("%ld: %p -> (%p, %p, %p, %p)\n", obj_number++, 762 printf("%ld: %p -> (%p, %p, %p, %p)\n", obj_number++,
765 entry->ptr, 763 entry->ptr,
diff --git a/src/lib/eo/eo_ptr_indirection2.x b/src/lib/eo/eo_ptr_indirection2.x
new file mode 100644
index 0000000000..e67b09d959
--- /dev/null
+++ b/src/lib/eo/eo_ptr_indirection2.x
@@ -0,0 +1,466 @@
1#include <assert.h>
2#ifdef HAVE_MMAP
3#include <sys/types.h>
4#include <sys/stat.h>
5#include <fcntl.h>
6#include <sys/mman.h>
7#endif
8
9
10#if SIZEOF_UINTPTR_T == 4
11# error I am not 32 bits
12/* 32 bits */
13# define BITS_ENTRY_ID 21
14# define BITS_GENERATION_COUNTER 7
15# define BITS_DOMAIN 2
16# define BITS_CLASS 1
17# define REF_TAG_SHIFT 31
18# define DROPPED_TABLES 0
19# define DROPPED_ENTRIES 4
20#else
21# ifndef EO_FULL64BIT
22/* 47 bits */
23# define BITS_ENTRY_ID 33
24# define BITS_GENERATION_COUNTER 10
25# define BITS_DOMAIN 2
26# define BITS_CLASS 1
27# define REF_TAG_SHIFT 46
28# define DROPPED_TABLES 2
29# define DROPPED_ENTRIES 3
30# else
31/* 64 bits */
32# define BITS_ENTRY_ID 33
33# define BITS_GENERATION_COUNTER 27
34# define BITS_DOMAIN 2
35# define BITS_CLASS 1
36# define REF_TAG_SHIFT 63
37# define DROPPED_TABLES 2
38# define DROPPED_ENTRIES 3
39# endif
40#endif
41
42#define MEM_PAGE_SIZE 4096
43#define EO_ALIGN_SIZE(size) eina_mempool_alignof(size)
44
45typedef unsigned int Generation_Counter;
46
47/* Shifts macros to manipulate the Eo id */
48#define SHIFT_DOMAIN (BITS_ENTRY_ID + BITS_GENERATION_COUNTER)
49#define SHIFT_ENTRY_ID (BITS_GENERATION_COUNTER)
50/* Maximum ranges - a few tables and entries are dropped to minimize the amount
51 * of wasted bytes, see _eo_id_mem_alloc */
52#define MAX_DOMAIN (1UL << BITS_DOMAIN)
53#define MAX_ENTRY_ID (1UL << BITS_ENTRY_ID)
54#define MAX_GENERATIONS (1UL << BITS_GENERATION_COUNTER)
55
56/* Masks */
57#define MASK_DOMAIN (MAX_DOMAIN - 1UL)
58#define MASK_ENTRY_ID ((1UL << BITS_ENTRY_ID) - 1UL)
59#define MASK_GENERATIONS (MAX_GENERATIONS - 1UL)
60#define MASK_OBJ_TAG (1UL << (REF_TAG_SHIFT))
61
62
63/* This only applies to classes. Used to artificially enlarge the class ids
64 * to reduce the likelihood of a clash with normal integers. */
65#define CLASS_TAG_SHIFT (REF_TAG_SHIFT - 1UL)
66#define MASK_CLASS_TAG (((Eo_Id) 1UL) << (CLASS_TAG_SHIFT))
67
68#define EO_ENTRIES_STEP 512
69//#define EO_ENTRY_LAST SIZE_MAX
70#define EO_ENTRY_NULL ((uintptr_t)0)
71
72
73typedef union
74{
75 struct {
76 _Eo_Object *ptr;
77 unsigned int generation;
78 } data;
79
80 struct {
81 uintptr_t null;
82 size_t next;
83 } meta;
84} Eo_Id_Entry;
85
86typedef struct
87{
88 struct {
89 Eo_Id id;
90 _Eo_Object *object;
91 const Eo *isa_id;
92 const Efl_Class *klass;
93 Eina_Bool isa;
94 } cache;
95
96 Eo_Id_Entry *entries;
97 size_t count;
98 size_t next;
99 unsigned int generation;
100
101 /* Optional */
102 Eina_Lock obj_lock;
103 Eina_Bool shared;
104} Eo_Id_Table;
105
106typedef struct
107{
108 Eo_Id_Table *tables[4];
109 int local_domain;
110 unsigned int stack_top;
111 unsigned char domain_stack[256 - (sizeof(void *) * 4) - (2 * sizeof(unsigned int))];
112} Eo_Id_Data;
113
114
115
116extern Eo_Id_Data *_eo_table_data_shared;
117extern Eo_Id_Table *_eo_table_data_shared_data;
118
119
120extern Eo_Id_Data _eo_main_id_data;
121extern Eo_Id_Table _eo_main_id_table;
122
123extern Eo_Id_Data *_eo_id_data;
124
125static inline void
126_eo_id_entries_setup(Eo_Id_Entry *ptr,
127 size_t count,
128 size_t start_index)
129{
130 const size_t end = count + start_index;
131 for (size_t i = start_index; i < end; i++)
132 {
133 ptr[i].meta.null = EO_ENTRY_NULL;
134 ptr[i].meta.next = i + 1;
135 }
136// ptr[end - 1].meta.null = EO_ENTRY_NULL;
137// ptr[end - 1].meta.next = EO_ENTRY_LAST;
138}
139
140static inline Eina_Bool
141_eo_id_table_setup(Eo_Id_Table *table)
142{
143 /* Allocate a first bunch of entries */
144 table->entries = malloc(sizeof(Eo_Id_Entry) * EO_ENTRIES_STEP);
145 if (EINA_UNLIKELY(! table->entries)) return EINA_FALSE;
146 table->count = EO_ENTRIES_STEP;
147 table->next = 0;
148
149 _eo_id_entries_setup(table->entries, table->count, 0);
150
151 return EINA_TRUE;
152}
153
154static inline Eo_Id_Table *
155_eo_id_table_new(Efl_Id_Domain domain)
156{
157 Eo_Id_Table *const table = calloc(1, sizeof(*table));
158 if (EINA_UNLIKELY(! table)) return NULL;
159
160 /* Initialize the array of entries */
161 if (EINA_UNLIKELY(! _eo_id_table_setup(table)))
162 goto free_table;
163
164 table->generation = rand() % MAX_GENERATIONS;
165
166 if (domain == EFL_ID_DOMAIN_SHARED)
167 {
168 if (!eina_lock_recursive_new(&(table->obj_lock)))
169 goto free_entries;
170 table->shared = EINA_TRUE;
171 }
172 return table;
173
174free_entries:
175 free(table->entries);
176free_table:
177 free(table);
178 return NULL;
179}
180
181static inline void
182_eo_id_table_clear(Eo_Id_Table *table)
183{
184 free(table->entries);
185 table->entries = NULL;
186 table->next = 0;
187 table->count = 0;
188
189 if (table->shared) eina_lock_free(&(table->obj_lock));
190}
191
192static inline void
193_eo_id_table_free(Eo_Id_Table *table)
194{
195 _eo_id_table_clear(table);
196 free(table);
197}
198
199
200static inline Eo_Id_Data *
201_eo_main_id_data_new(void)
202{
203 Eo_Id_Data *const d = &_eo_main_id_data;
204 d->local_domain = EFL_ID_DOMAIN_MAIN;
205 d->domain_stack[d->stack_top] = EFL_ID_DOMAIN_MAIN;
206 d->tables[EFL_ID_DOMAIN_MAIN] = &_eo_main_id_table;
207 d->tables[EFL_ID_DOMAIN_SHARED] = _eo_table_data_shared_data;
208
209 /* Init table */
210 _eo_id_table_setup(&_eo_main_id_table);
211
212 return d;
213}
214
215static inline Eo_Id_Data *
216_eo_id_data_new(Efl_Id_Domain domain)
217{
218 if (domain == EFL_ID_DOMAIN_MAIN)
219 return _eo_main_id_data_new();
220
221 Eo_Id_Data *const data = calloc(1, sizeof(Eo_Id_Data));
222 if (EINA_UNLIKELY(! data)) return NULL;
223
224 data->local_domain = domain;
225 data->domain_stack[data->stack_top] = data->local_domain;
226 data->tables[data->local_domain] =
227 _eo_id_table_new(data->local_domain);
228 if (domain != EFL_ID_DOMAIN_SHARED)
229 data->tables[EFL_ID_DOMAIN_SHARED] = _eo_table_data_shared_data;
230 return data;
231}
232
233static inline Eo_Id_Data *
234_eo_id_data_get(void)
235{
236 return _eo_id_data;
237}
238
239static inline Eo_Id_Table *
240_eo_current_table_get(Eo_Id_Data *data)
241{
242 return data->tables[data->domain_stack[data->stack_top]];
243}
244
245static inline Eo_Id_Table *
246_eo_id_data_table_get(Eo_Id_Data *data, Efl_Id_Domain domain)
247{
248 return data->tables[domain];
249}
250
251static inline Eina_Bool
252_eo_id_domain_compatible(const Eo *o1, const Eo *o2)
253{
254 Efl_Id_Domain domain1 = ((Eo_Id)o1 >> SHIFT_DOMAIN) & MASK_DOMAIN;
255 Efl_Id_Domain domain2 = ((Eo_Id)o2 >> SHIFT_DOMAIN) & MASK_DOMAIN;
256 if (domain1 == domain2) return EINA_TRUE;
257 ERR("Object %p and %p are not compatible. Domain %i and %i do not match",
258 o1, o2, domain1, domain2);
259 return EINA_FALSE;
260}
261
262static inline void
263_eo_obj_pointer_done(const Eo_Id obj_id)
264{
265 Efl_Id_Domain domain = (obj_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
266 if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED)) return;
267 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
268}
269
270//////////////////////////////////////////////////////////////////////////
271
272
273/* Macro used to compose an Eo id */
274#define EO_COMPOSE_ID(ENTRY, DOMAIN, GENERATION) \
275 (((Eo_Id) 0x1 << REF_TAG_SHIFT) | \
276 (((Eo_Id)DOMAIN & MASK_DOMAIN) << SHIFT_DOMAIN) | \
277 (((Eo_Id)ENTRY & MASK_ENTRY_ID) << SHIFT_ENTRY_ID) | \
278 ((Eo_Id)GENERATION & MASK_GENERATIONS))
279
280/* Macro to extract from an Eo id the indexes of the tables */
281#define EO_DECOMPOSE_ID(ID, ENTRY, GENERATION) \
282 ENTRY = (ID >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; \
283 GENERATION = ID & MASK_GENERATIONS;
284
285
286static inline Eo_Id_Entry *
287_eo_id_table_next_entry_get(Eo_Id_Table *table,
288 size_t *idx_out)
289{
290 /* The table is saturated with Eo IDs. Give it more room. */
291 if (EINA_UNLIKELY(table->next == table->count))
292 {
293 const size_t new_count = table->count + EO_ENTRIES_STEP;
294 // XXX Unlikely to overflow.
295 Eo_Id_Entry *const tmp = realloc(table->entries, new_count * sizeof(Eo_Id_Entry));
296 if (EINA_UNLIKELY(! tmp))
297 {
298 CRI("Failed to reallocate %zu elements", new_count);
299 return NULL;
300 }
301
302 _eo_id_entries_setup(tmp, EO_ENTRIES_STEP, table->count);
303
304 table->entries = tmp;
305 table->count = new_count;
306 }
307 else if (EINA_UNLIKELY(table->next > table->count))
308 {
309 CRI("Invalid");
310 return NULL;
311 }
312
313 *idx_out = table->next;
314 Eo_Id_Entry *const entry = &(table->entries[table->next]);
315 if (EINA_UNLIKELY(entry->meta.null != EO_ENTRY_NULL))
316 {
317 CRI("Boom. Eo is broken. Cell %zu is not free, but was expected to be...", *idx_out);
318 return NULL;
319 }
320 table->next = entry->meta.next;
321
322 return entry;
323}
324
325static inline void
326_eo_id_table_entry_release(Eo_Id_Table *table,
327 size_t index)
328{
329 Eo_Id_Entry *const entry = &(table->entries[index]);
330 entry->meta.null = EO_ENTRY_NULL; /* This will annihilate the contents of ptr */
331 entry->meta.next = table->next;
332 table->next = index;
333}
334
335static inline Eo_Id
336_eo_id_allocate(const _Eo_Object *obj, const Eo *parent_id)
337{
338 Eo_Id_Table *table;
339 Eo_Id id = 0;
340
341
342 Eo_Id_Data *const data = _eo_id_data_get();
343 if (parent_id)
344 {
345 const Efl_Id_Domain domain = ((Eo_Id)parent_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
346 table = _eo_id_data_table_get(data, domain);
347 }
348 else table = _eo_current_table_get(data);
349 if (EINA_UNLIKELY(!table)) return 0;
350
351
352 const Eo_Id domain = (table->shared)
353 ? EFL_ID_DOMAIN_SHARED
354 : data->domain_stack[data->stack_top];
355
356 if (EINA_UNLIKELY(! table->shared))
357 eina_lock_take(&(_eo_table_data_shared_data->obj_lock));
358
359
360 size_t idx;
361 Eo_Id_Entry *const entry = _eo_id_table_next_entry_get(table, &idx);
362 if (EINA_UNLIKELY(! entry)) goto fail;
363
364 /* [1;max-1] thus we never generate an Eo_Id equal to 0 */
365 table->generation++;
366 if (table->generation >= MAX_GENERATIONS) table->generation = 1;
367 /* Fill the entry and return it's Eo Id */
368 entry->data.ptr = (_Eo_Object *)obj;
369 entry->data.generation = table->generation;
370 id = EO_COMPOSE_ID(idx, domain, entry->data.generation);
371
372
373fail:
374 if (EINA_UNLIKELY(! table->shared))
375 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
376
377 return id;
378}
379
380static inline void
381_eo_id_release(Eo_Id id)
382{
383 const Efl_Id_Domain domain = (id >> SHIFT_DOMAIN) & MASK_DOMAIN;
384 Eo_Id_Data *const data = _eo_id_data_get();
385 Eo_Id_Table *const table = _eo_id_data_table_get(data, domain);
386 if (EINA_UNLIKELY(! table)) return;
387
388 size_t entry_id;
389 unsigned int generation;
390 EO_DECOMPOSE_ID(id, entry_id, generation);
391
392 if (EINA_UNLIKELY(domain == EFL_ID_DOMAIN_SHARED))
393 eina_lock_take(&(_eo_table_data_shared_data->obj_lock));
394
395 /* If the entry index is out of bounds, that sucks... We never "ungrow"
396 * so this is definitely pure garbage. */
397 if (EINA_UNLIKELY(entry_id >= table->count))
398 {
399 ERR("Invalid entry id %zu >= %zu", entry_id, table->count);
400 goto fail;
401 }
402
403 /* We are now sure that the object MAY have been allocated. At least we
404 * won't segfault trying to access it. */
405 const Eo_Id_Entry *const entry = &(table->entries[entry_id]);
406
407 /* If the entry has its 'null' field set to 0, it is highly probable that
408 * the object has already been freed. */
409 if (EINA_UNLIKELY(entry->meta.null == EO_ENTRY_NULL))
410 {
411 ERR("meta is already null");
412 goto fail;
413 }
414
415 /* If the generation count mismatch, the pointer is garbage */
416 if (EINA_UNLIKELY(entry->data.generation != generation))
417 {
418 ERR("ID: %p. invalid generation count: %u vs %u", (void*)id,entry->data.generation, generation);
419 goto fail;
420 }
421
422 /* At this point we are almost sure that the object IS valid. We can release
423 * the Eo Id. */
424 _eo_id_table_entry_release(table, entry_id);
425
426 /* If we destroyed the ID that was in the table cache wipe out the cache */
427 if (table->cache.id == id)
428 {
429 table->cache.id = 0;
430 table->cache.object = NULL;
431 }
432 if ((Eo_Id)table->cache.isa_id == id)
433 {
434 table->cache.isa_id = NULL;
435 table->cache.klass = NULL;
436 table->cache.isa = EINA_FALSE;
437 }
438
439 if (EINA_UNLIKELY(domain == EFL_ID_DOMAIN_SHARED))
440 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
441 return;
442
443fail:
444 if (EINA_UNLIKELY(domain == EFL_ID_DOMAIN_SHARED))
445 eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
446 ERR("obj_id %p is not pointing to a valid object. Maybe it has already been freed.", (void *)id);
447}
448
449
450#ifdef EFL_DEBUG
451static inline void
452_eo_print(const Eo_Id_Table *table)
453{
454 unsigned int object = 0;
455 for (size_t i = 0; i < table->count; i++)
456 {
457 const Eo_Id_Entry *const entry = &(table->entries[i]);
458 if (entry->meta.null != EO_ENTRY_NULL)
459 {
460 printf("%u[%zu]: %p -> (%u)\n",
461 object, i, entry->data.ptr, entry->data.generation);
462 object++;
463 }
464 }
465}
466#endif