diff options
author | Jean Guyomarc'h <jean@guyomarch.bzh> | 2018-01-13 11:25:05 +0100 |
---|---|---|
committer | Jean Guyomarc'h <jean@guyomarch.bzh> | 2018-01-13 11:25:05 +0100 |
commit | 96dc5e1ef34869e792b5f83cd38bfb92332e5a07 (patch) | |
tree | 9f5eafa845a490b91e2accc53b33c5e0f09d8332 | |
parent | af2d961047ca03149c5342e633344570670020e0 (diff) | |
download | efl-96dc5e1ef34869e792b5f83cd38bfb92332e5a07.tar.gz |
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.c | 258 | ||||
-rw-r--r-- | src/lib/eo/eo_ptr_indirection.c | 183 | ||||
-rw-r--r-- | src/lib/eo/eo_ptr_indirection.h | 8 | ||||
-rw-r--r-- | src/lib/eo/eo_ptr_indirection.x | 12 | ||||
-rw-r--r-- | src/lib/eo/eo_ptr_indirection2.x | 466 |
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: EAPI Eina_Bool efl_isa(const Eo *eo_id, const Efl_Class *klass_id) { - Efl_Id_Domain domain; - Eo_Id_Data *data; - Eo_Id_Table_Data *tdata; - Eina_Bool isa = EINA_FALSE; if (EINA_UNLIKELY(!eo_id)) return EINA_FALSE; - domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN; - data = _eo_table_data_get(); - tdata = _eo_table_data_table_get(data, domain); - if (EINA_UNLIKELY(!tdata)) goto err; + const Efl_Id_Domain domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN; + Eo_Id_Data *const data = _eo_id_data_get(); + Eo_Id_Table *const table = _eo_id_data_table_get(data, domain); + if (EINA_UNLIKELY(!table)) goto err; + + Eina_Bool isa = EINA_FALSE; if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED)) { - if ((tdata->cache.isa_id == eo_id) && - (tdata->cache.klass == klass_id)) + if ((table->cache.isa_id == eo_id) && + (table->cache.klass == klass_id)) { - isa = tdata->cache.isa; + isa = table->cache.isa; return isa; } EO_OBJ_POINTER_GOTO(eo_id, obj, err_obj); EO_CLASS_POINTER_GOTO(klass_id, klass, err_class); - const op_type_funcs *func = _vtable_func_get + const op_type_funcs *const func = _vtable_func_get (EO_VTABLE(obj), klass->base_id + klass->ops_count); // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it. - tdata->cache.isa_id = eo_id; - tdata->cache.klass = klass_id; + table->cache.isa_id = eo_id; + table->cache.klass = klass_id; // Currently implemented by reusing the LAST op id. Just marking it with // _eo_class_isa_func. - isa = tdata->cache.isa = (func && (func->func == _eo_class_isa_func)); + isa = table->cache.isa = (func && (func->func == _eo_class_isa_func)); } else { eina_lock_take(&(_eo_table_data_shared_data->obj_lock)); - if ((tdata->cache.isa_id == eo_id) && - (tdata->cache.klass == klass_id)) + if ((table->cache.isa_id == eo_id) && + (table->cache.klass == klass_id)) { - isa = tdata->cache.isa; + isa = table->cache.isa; // since this is the cache we hope this gets a lot of hits and // thus lets assume the hit is the mot important thing thus // 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) EO_OBJ_POINTER_GOTO(eo_id, obj, err_shared_obj); EO_CLASS_POINTER_GOTO(klass_id, klass, err_shared_class); - const op_type_funcs *func = _vtable_func_get + const op_type_funcs *const func = _vtable_func_get (EO_VTABLE(obj), klass->base_id + klass->ops_count); // Caching the result as we do a lot of serial efl_isa due to evas_object_image using it. - tdata->cache.isa_id = eo_id; - tdata->cache.klass = klass_id; + table->cache.isa_id = eo_id; + table->cache.klass = klass_id; // Currently implemented by reusing the LAST op id. Just marking it with // _eo_class_isa_func. - isa = tdata->cache.isa = (func && (func->func == _eo_class_isa_func)); + isa = table->cache.isa = (func && (func->func == _eo_class_isa_func)); EO_OBJ_DONE(eo_id); eina_lock_release(&(_eo_table_data_shared_data->obj_lock)); } @@ -2177,12 +2175,12 @@ efl_data_xunref_internal(const Eo *obj_id, void *data, const Eo *ref_obj_id) EO_OBJ_DONE(obj_id); } -static void -_eo_table_del_cb(void *in) -{ - Eo_Id_Data *data = in; - _eo_free_ids_tables(data); -} +//static void +//_eo_table_del_cb(void *in) +//{ +// Eo_Id_Data *data = in; +// _eo_free_ids_tables(data); +//} /* FIXME: Support other domains and tables, at the moment only the main * domain and table. @@ -2244,7 +2242,7 @@ efl_object_init(void) _ops_storage = eina_hash_string_superfast_new(NULL); #endif - _eo_table_data_shared = _eo_table_data_new(EFL_ID_DOMAIN_SHARED); + _eo_table_data_shared = _eo_id_data_new(EFL_ID_DOMAIN_SHARED); if (!_eo_table_data_shared) { ERR("Could not allocate shared table data"); @@ -2253,20 +2251,13 @@ efl_object_init(void) _eo_table_data_shared_data = _eo_table_data_shared->tables[EFL_ID_DOMAIN_SHARED]; // specially force eoid data to be creanted so we can switch it to domain 0 - Eo_Id_Data *data = _eo_table_data_new(EFL_ID_DOMAIN_MAIN); - _eo_gdb_main_domain = data; - if (!data) + _eo_id_data = _eo_id_data_new(EFL_ID_DOMAIN_MAIN); + _eo_gdb_main_domain = _eo_id_data; + if (EINA_UNLIKELY(!_eo_id_data)) { ERR("Could not allocate main table data"); return EINA_FALSE; } - if (!eina_tls_cb_new(&_eo_table_data, _eo_table_del_cb)) - { - ERR("Could not allocate TLS for eo domain data"); - _eo_table_del_cb(data); - return EINA_FALSE; - } - eina_tls_set(_eo_table_data, data); _efl_object_main_thread = eina_thread_self(); #ifdef EO_DEBUG @@ -2326,11 +2317,10 @@ efl_object_shutdown(void) eina_spinlock_free(&_ops_storage_lock); eina_lock_free(&_efl_class_creation_lock); - _eo_free_ids_tables(_eo_table_data_get()); - eina_tls_free(_eo_table_data); +// _eo_free_ids_tables(_eo_id_data_get()); if (_eo_table_data_shared) { - _eo_free_ids_tables(_eo_table_data_shared); + //_eo_free_ids_tables(_eo_table_data_shared); _eo_table_data_shared = NULL; _eo_table_data_shared_data = NULL; } @@ -2354,21 +2344,21 @@ efl_object_shutdown(void) EAPI Efl_Id_Domain efl_domain_get(void) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); return data->local_domain; } EAPI Efl_Id_Domain efl_domain_current_get(void) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); return data->domain_stack[data->stack_top]; } EAPI Eina_Bool efl_domain_switch(Efl_Id_Domain domain) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD) || (domain == EFL_ID_DOMAIN_SHARED)) { @@ -2378,12 +2368,12 @@ efl_domain_switch(Efl_Id_Domain domain) if (data) { if (data->local_domain == domain) return EINA_TRUE; - _eo_free_ids_tables(data); + //_eo_free_ids_tables(data); } - data = _eo_table_data_new(domain); + data = _eo_id_data_new(domain); data->local_domain = domain; data->domain_stack[data->stack_top] = domain; - eina_tls_set(_eo_table_data, data); + _eo_id_data = data; return EINA_TRUE; } @@ -2410,21 +2400,21 @@ _efl_domain_pop(Eo_Id_Data *data) EAPI Eina_Bool efl_domain_current_push(Efl_Id_Domain domain) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); return _efl_domain_push(data, domain); } EAPI void efl_domain_current_pop(void) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); _efl_domain_pop(data); } EAPI Eina_Bool efl_domain_current_set(Efl_Id_Domain domain) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD)) { ERR("Invalid domain %i being set", domain); @@ -2437,14 +2427,14 @@ efl_domain_current_set(Efl_Id_Domain domain) EAPI Efl_Domain_Data * efl_domain_data_get(void) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); return (Efl_Domain_Data *)data; } EAPI Efl_Id_Domain efl_domain_data_adopt(Efl_Domain_Data *data_in) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); Eo_Id_Data *data_foreign = (Eo_Id_Data *)data_in; if (!data_foreign) @@ -2472,7 +2462,7 @@ efl_domain_data_adopt(Efl_Domain_Data *data_in) EAPI Eina_Bool efl_domain_data_return(Efl_Id_Domain domain) { - Eo_Id_Data *data = _eo_table_data_get(); + Eo_Id_Data *data = _eo_id_data_get(); if ((domain < EFL_ID_DOMAIN_MAIN) || (domain > EFL_ID_DOMAIN_THREAD)) { @@ -3290,86 +3280,86 @@ eo_classes_iterator_new(void) return (Eina_Iterator *)it; } -typedef struct -{ - Eina_Iterator iterator; - Eo_Id_Table_Data *tdata; - Table_Index mid_table_id; - Table_Index table_id; - Table_Index entry_id; -} _Eo_Objects_Iterator; - -static Eina_Bool -_eo_objects_iterator_next(Eina_Iterator *it, void **data) -{ - Table_Index mid_table_id, table_id, entry_id; - Eo_Id_Table_Data *tdata; - _Eo_Objects_Iterator *eo_it = (_Eo_Objects_Iterator *)it; - if (!eo_it->tdata) return EINA_FALSE; - - tdata = eo_it->tdata; - mid_table_id = eo_it->mid_table_id; - table_id = eo_it->table_id; - entry_id = eo_it->entry_id; - while (mid_table_id < MAX_MID_TABLE_ID) - { - if (tdata->eo_ids_tables[mid_table_id]) - { - while (table_id < MAX_TABLE_ID) - { - if (TABLE_FROM_IDS) - { - while (entry_id < MAX_ENTRY_ID) - { - _Eo_Id_Entry *entry = &(TABLE_FROM_IDS->entries[entry_id]); - if (entry->active) - { - Eo *obj = _eo_header_id_get((Eo_Header *) entry->ptr); - *data = obj; - eo_it->mid_table_id = mid_table_id; - eo_it->table_id = table_id; - eo_it->entry_id = entry_id + 1; - return EINA_TRUE; - } - entry_id++; - } - entry_id = 0; - } - table_id++; - } - table_id = 0; - } - mid_table_id++; - } - return EINA_FALSE; -} - -static void -_eo_objects_iterator_free(Eina_Iterator *it) -{ - EINA_MAGIC_SET(it, EINA_MAGIC_NONE); - free(it); -} - -EAPI Eina_Iterator * -eo_objects_iterator_new(void) -{ - _Eo_Objects_Iterator *it; - Eo_Id_Table_Data *tdata = _eo_table_data_table_get(_eo_table_data_get(), EFL_ID_DOMAIN_MAIN); - - if (!tdata) return NULL; - - it = calloc(1, sizeof (*it)); - if (!it) return NULL; - - it->tdata = tdata; - it->iterator.version = EINA_ITERATOR_VERSION; - it->iterator.next = _eo_objects_iterator_next; - it->iterator.free = _eo_objects_iterator_free; - EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); - - return (Eina_Iterator *)it; -} +///typedef struct +///{ +/// Eina_Iterator iterator; +/// Eo_Id_Table_Data *tdata; +/// Table_Index mid_table_id; +/// Table_Index table_id; +/// Table_Index entry_id; +///} _Eo_Objects_Iterator; +/// +///static Eina_Bool +///_eo_objects_iterator_next(Eina_Iterator *it, void **data) +///{ +/// Table_Index mid_table_id, table_id, entry_id; +/// Eo_Id_Table_Data *tdata; +/// _Eo_Objects_Iterator *eo_it = (_Eo_Objects_Iterator *)it; +/// if (!eo_it->tdata) return EINA_FALSE; +/// +/// tdata = eo_it->tdata; +/// mid_table_id = eo_it->mid_table_id; +/// table_id = eo_it->table_id; +/// entry_id = eo_it->entry_id; +/// while (mid_table_id < MAX_MID_TABLE_ID) +/// { +/// if (tdata->eo_ids_tables[mid_table_id]) +/// { +/// while (table_id < MAX_TABLE_ID) +/// { +/// if (TABLE_FROM_IDS) +/// { +/// while (entry_id < MAX_ENTRY_ID) +/// { +/// _Eo_Id_Entry *entry = &(TABLE_FROM_IDS->entries[entry_id]); +/// if (entry->generation != 0) +/// { +/// Eo *obj = _eo_header_id_get((Eo_Header *) entry->ptr); +/// *data = obj; +/// eo_it->mid_table_id = mid_table_id; +/// eo_it->table_id = table_id; +/// eo_it->entry_id = entry_id + 1; +/// return EINA_TRUE; +/// } +/// entry_id++; +/// } +/// entry_id = 0; +/// } +/// table_id++; +/// } +/// table_id = 0; +/// } +/// mid_table_id++; +/// } +/// return EINA_FALSE; +///} +/// +///static void +///_eo_objects_iterator_free(Eina_Iterator *it) +///{ +/// EINA_MAGIC_SET(it, EINA_MAGIC_NONE); +/// free(it); +///} +/// +///EAPI Eina_Iterator * +///eo_objects_iterator_new(void) +///{ +/// _Eo_Objects_Iterator *it; +/// Eo_Id_Table_Data *tdata = _eo_id_data_table_get(_eo_id_data_get(), EFL_ID_DOMAIN_MAIN); +/// +/// if (!tdata) return NULL; +/// +/// it = calloc(1, sizeof (*it)); +/// if (!it) return NULL; +/// +/// it->tdata = tdata; +/// it->iterator.version = EINA_ITERATOR_VERSION; +/// it->iterator.next = _eo_objects_iterator_next; +/// it->iterator.free = _eo_objects_iterator_free; +/// EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); +/// +/// return (Eina_Iterator *)it; +///} static Eina_Bool _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; ////////////////////////////////////////////////////////////////////////// -Eina_TLS _eo_table_data; -Eo_Id_Data *_eo_table_data_shared = NULL; -Eo_Id_Table_Data *_eo_table_data_shared_data = NULL; +Eo_Id_Data *_eo_table_data_shared; +Eo_Id_Table *_eo_table_data_shared_data; -Eo_Id_Data _eo_main_table_data; -Eo_Id_Table_Data _eo_table_main_table_data; + +Eo_Id_Data _eo_main_id_data; +Eo_Id_Table _eo_main_id_table; + +Eo_Id_Data *_eo_id_data; ////////////////////////////////////////////////////////////////////////// @@ -74,7 +76,7 @@ _eo_obj_pointer_invalid(const Eo_Id obj_id, (data->tables[2]) ? "2" : " ", (data->tables[3]) ? "3" : " ", (unsigned long)(obj_id & MASK_GENERATIONS), - (unsigned long)(obj_id >> SHIFT_ENTRY_ID) & (MAX_ENTRY_ID | MAX_TABLE_ID | MAX_MID_TABLE_ID), + (unsigned long)((obj_id >> SHIFT_ENTRY_ID)) & MASK_ENTRY_ID, (int)(obj_id >> REF_TAG_SHIFT) & 0x1); _eo_log_obj_report(obj_id, EINA_LOG_LEVEL_ERR, func_name, file, line); } @@ -98,48 +100,37 @@ _eo_obj_pointer_get(const Eo_Id obj_id, const char *restrict func_name, const ch do_domain_main: EINA_HOT { - __builtin_prefetch(&_eo_table_main_table_data, 0, 3); - if (obj_id == _eo_table_main_table_data.cache.id) - return _eo_table_main_table_data.cache.object; +// __builtin_prefetch(&_eo_main_id_table, 0, 3); + if (obj_id == _eo_main_id_table.cache.id) + return _eo_main_id_table.cache.object; /* XXX This could definitely be done in one go with vectorization */ - const unsigned int mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; - const unsigned int table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID; - const unsigned int entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; - const Generation_Counter generation = obj_id & MASK_GENERATIONS; + const size_t entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; + const unsigned int generation = obj_id & MASK_GENERATIONS; // get tag bit to check later down below - pipelining const Eo_Id tag_bit = (obj_id) & MASK_OBJ_TAG; - if (EINA_UNLIKELY(!tag_bit)) goto main_err; + if (EINA_UNLIKELY(!tag_bit || + (entry_id >= _eo_main_id_table.count))) + goto main_err; - __builtin_prefetch(&(_eo_table_main_table_data.eo_ids_tables[mid_table_id]), 0, 3); - // Check the validity of the entry - if (EINA_LIKELY(_eo_table_main_table_data.eo_ids_tables[mid_table_id] != NULL)) + register const Eo_Id_Entry *const entry = &(_eo_main_id_table.entries[entry_id]); +// __builtin_prefetch(entry, 0, 0); + if (EINA_LIKELY(entry->data.generation == generation)) { - register const _Eo_Ids_Table *const tab = - _eo_table_main_table_data.eo_ids_tables[mid_table_id][table_id]; - - if (EINA_LIKELY(tab != NULL)) - { - register const _Eo_Id_Entry *const entry = &(tab->entries[entry_id]); - if (EINA_LIKELY(entry->active && (entry->generation == generation))) - { - // Cache the result of that lookup - _eo_table_main_table_data.cache.object = entry->ptr; - _eo_table_main_table_data.cache.id = obj_id; - return _eo_table_main_table_data.cache.object; - } - } + // Cache the result of that lookup + _eo_main_id_table.cache.object = entry->data.ptr; + _eo_main_id_table.cache.id = obj_id; + return _eo_main_id_table.cache.object; } - goto main_err; } main_err: EINA_COLD - _eo_obj_pointer_invalid(obj_id, &_eo_main_table_data, domain, func_name, file, line); + _eo_obj_pointer_invalid(obj_id, &_eo_main_id_data, domain, func_name, file, line); return NULL; @@ -147,55 +138,30 @@ main_err: EINA_COLD do_domain_thread: EINA_COLD do_domain_other: EINA_COLD { - _Eo_Id_Entry *entry; - Generation_Counter generation; - unsigned int mid_table_id, table_id, entry_id; - Eo_Id tag_bit; - Eo_Id_Data *data; - Eo_Id_Table_Data *tdata; - - - // NULL objects will just be sensibly ignored. not worth complaining - // every single time. - - data = _eo_table_data_get(); - EINA_PREFETCH(&(data->tables[0])); - tdata = _eo_table_data_table_get(data, domain); - EINA_PREFETCH(&(tdata->cache.id)); - if (EINA_UNLIKELY(!tdata)) goto err; + Eo_Id_Data *const data = _eo_id_data_get(); + Eo_Id_Table *const table = _eo_id_data_table_get(data, domain); + if (EINA_UNLIKELY(!table)) goto err; - if (obj_id == tdata->cache.id) - return tdata->cache.object; + if (obj_id == table->cache.id) + return table->cache.object; - mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; - EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id])); - table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID; - entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; - generation = obj_id & MASK_GENERATIONS; + const size_t entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; + const unsigned int generation = obj_id & MASK_GENERATIONS; // get tag bit to check later down below - pipelining - tag_bit = (obj_id) & MASK_OBJ_TAG; - if (EINA_UNLIKELY(!obj_id)) goto err_null; - else if (EINA_UNLIKELY(!tag_bit)) goto err; - - // Check the validity of the entry - if (tdata->eo_ids_tables[mid_table_id]) - { - _Eo_Ids_Table *tab = TABLE_FROM_IDS; - - if (tab) - { - entry = &(tab->entries[entry_id]); - if (entry->active && (entry->generation == generation)) - { - // Cache the result of that lookup - tdata->cache.object = entry->ptr; - tdata->cache.id = obj_id; - return entry->ptr; - } - } - } + const Eo_Id tag_bit = (obj_id) & MASK_OBJ_TAG; + if (EINA_UNLIKELY(!tag_bit || + (entry_id >= table->count))) goto err; + + register const Eo_Id_Entry *const entry = &(table->entries[entry_id]); + if (EINA_LIKELY(entry->data.generation == generation)) + { + // Cache the result of that lookup + table->cache.object = entry->data.ptr; + table->cache.id = obj_id; + return entry->data.ptr; + } goto err; err_null: EINA_COLD @@ -207,57 +173,34 @@ err: EINA_COLD do_domain_shared: EINA_COLD { - _Eo_Id_Entry *entry; - Generation_Counter generation; - unsigned int mid_table_id, table_id, entry_id; - Eo_Id tag_bit; - Eo_Id_Data *data; - Eo_Id_Table_Data *tdata; - - data = _eo_table_data_get(); - EINA_PREFETCH(&(data->tables[0])); - tdata = _eo_table_data_table_get(data, domain); - EINA_PREFETCH(&(tdata->cache.id)); - if (EINA_UNLIKELY(!tdata)) goto err_shared_err; - - - eina_lock_take(&(_eo_table_data_shared_data->obj_lock)); - if (EINA_LIKELY(obj_id == tdata->cache.id)) + Eo_Id_Data *const data = _eo_table_data_shared; + Eo_Id_Table *const table = _eo_table_data_shared_data; + + eina_lock_take(&(table->obj_lock)); + if (EINA_LIKELY(obj_id == table->cache.id)) // yes we return keeping the lock locked. thats why // you must call _eo_obj_pointer_done() wrapped // by EO_OBJ_DONE() to release - return tdata->cache.object; + return table->cache.object; - mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID; - EINA_PREFETCH(&(tdata->eo_ids_tables[mid_table_id])); - table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID; - entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; - generation = obj_id & MASK_GENERATIONS; + const size_t entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; + const unsigned int generation = obj_id & MASK_GENERATIONS; // get tag bit to check later down below - pipelining - tag_bit = (obj_id) & MASK_OBJ_TAG; - if (!obj_id) goto err_shared_null; - else if (!tag_bit) goto err_shared; + const Eo_Id tag_bit = (obj_id) & MASK_OBJ_TAG; + if (EINA_UNLIKELY((!tag_bit || + entry_id >= table->count))) goto err_shared; - // Check the validity of the entry - if (tdata->eo_ids_tables[mid_table_id]) + Eo_Id_Entry *const entry = &(table->entries[entry_id]); + if (EINA_LIKELY(entry->data.generation == generation)) { - _Eo_Ids_Table *tab = TABLE_FROM_IDS; - - if (tab) - { - entry = &(tab->entries[entry_id]); - if (entry->active && (entry->generation == generation)) - { - // Cache the result of that lookup - tdata->cache.object = entry->ptr; - tdata->cache.id = obj_id; - // yes we return keeping the lock locked. thats why - // you must call _eo_obj_pointer_done() wrapped - // by EO_OBJ_DONE() to release - return entry->ptr; - } - } + // Cache the result of that lookup + table->cache.object = entry->data.ptr; + table->cache.id = obj_id; + // yes we return keeping the lock locked. thats why + // you must call _eo_obj_pointer_done() wrapped + // by EO_OBJ_DONE() to release + return entry->data.ptr; } goto err_shared; 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 static inline void _eo_print(Eo_Id_Table_Data *tdata); #endif -extern Eina_TLS _eo_table_data; +//extern Eina_TLS _eo_table_data; -#include "eo_ptr_indirection.x" +#include "eo_ptr_indirection2.x" -extern Eo_Id_Data *_eo_table_data_shared; -extern Eo_Id_Table_Data *_eo_table_data_shared_data; +//extern Eo_Id_Data *_eo_table_data_shared; +//extern Eo_Id_Table_Data *_eo_table_data_shared_data; #endif 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) if (tdata->generation >= MAX_GENERATIONS) tdata->generation = 1; /* Fill the entry and return it's Eo Id */ entry->ptr = (_Eo_Object *)obj; - entry->active = 1; entry->generation = tdata->generation; PROTECT(tdata->current_table); 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) if (tdata->generation == MAX_GENERATIONS) tdata->generation = 1; /* Fill the entry and return it's Eo Id */ entry->ptr = (_Eo_Object *)obj; - entry->active = 1; entry->generation = tdata->generation; PROTECT(tdata->current_table); id = EO_COMPOSE_FINAL_ID(tdata->current_table->partial_id, @@ -611,12 +609,12 @@ _eo_id_release(const Eo_Id obj_id) if (tdata->eo_ids_tables[mid_table_id] && (table = TABLE_FROM_IDS)) { entry = &(table->entries[entry_id]); - if (entry && entry->active && (entry->generation == generation)) + if (entry->generation == generation) { UNPROTECT(table); table->free_entries++; // Disable the entry - entry->active = 0; + entry->generation = 0; entry->next_in_fifo = -1; // Push the entry into the fifo if (table->fifo_tail == -1) @@ -661,12 +659,12 @@ _eo_id_release(const Eo_Id obj_id) if (tdata->eo_ids_tables[mid_table_id] && (table = TABLE_FROM_IDS)) { entry = &(table->entries[entry_id]); - if (entry && entry->active && (entry->generation == generation)) + if (entry->generation == generation) { UNPROTECT(table); table->free_entries++; // Disable the entry - entry->active = 0; + entry->generation = 0; entry->next_in_fifo = -1; // Push the entry into the fifo if (table->fifo_tail == -1) @@ -759,7 +757,7 @@ _eo_print(Eo_Id_Table_Data *tdata) for (Table_Index entry_id = 0; entry_id < MAX_ENTRY_ID; entry_id++) { entry = &(TABLE_FROM_IDS->entries[entry_id]); - if (entry->active) + if (entry->generation != 0) { printf("%ld: %p -> (%p, %p, %p, %p)\n", obj_number++, 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 @@ +#include <assert.h> +#ifdef HAVE_MMAP +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mman.h> +#endif + + +#if SIZEOF_UINTPTR_T == 4 +# error I am not 32 bits +/* 32 bits */ +# define BITS_ENTRY_ID 21 +# define BITS_GENERATION_COUNTER 7 +# define BITS_DOMAIN 2 +# define BITS_CLASS 1 +# define REF_TAG_SHIFT 31 +# define DROPPED_TABLES 0 +# define DROPPED_ENTRIES 4 +#else +# ifndef EO_FULL64BIT +/* 47 bits */ +# define BITS_ENTRY_ID 33 +# define BITS_GENERATION_COUNTER 10 +# define BITS_DOMAIN 2 +# define BITS_CLASS 1 +# define REF_TAG_SHIFT 46 +# define DROPPED_TABLES 2 +# define DROPPED_ENTRIES 3 +# else +/* 64 bits */ +# define BITS_ENTRY_ID 33 +# define BITS_GENERATION_COUNTER 27 +# define BITS_DOMAIN 2 +# define BITS_CLASS 1 +# define REF_TAG_SHIFT 63 +# define DROPPED_TABLES 2 +# define DROPPED_ENTRIES 3 +# endif +#endif + +#define MEM_PAGE_SIZE 4096 +#define EO_ALIGN_SIZE(size) eina_mempool_alignof(size) + +typedef unsigned int Generation_Counter; + +/* Shifts macros to manipulate the Eo id */ +#define SHIFT_DOMAIN (BITS_ENTRY_ID + BITS_GENERATION_COUNTER) +#define SHIFT_ENTRY_ID (BITS_GENERATION_COUNTER) +/* Maximum ranges - a few tables and entries are dropped to minimize the amount + * of wasted bytes, see _eo_id_mem_alloc */ +#define MAX_DOMAIN (1UL << BITS_DOMAIN) +#define MAX_ENTRY_ID (1UL << BITS_ENTRY_ID) +#define MAX_GENERATIONS (1UL << BITS_GENERATION_COUNTER) + +/* Masks */ +#define MASK_DOMAIN (MAX_DOMAIN - 1UL) +#define MASK_ENTRY_ID ((1UL << BITS_ENTRY_ID) - 1UL) +#define MASK_GENERATIONS (MAX_GENERATIONS - 1UL) +#define MASK_OBJ_TAG (1UL << (REF_TAG_SHIFT)) + + +/* This only applies to classes. Used to artificially enlarge the class ids + * to reduce the likelihood of a clash with normal integers. */ +#define CLASS_TAG_SHIFT (REF_TAG_SHIFT - 1UL) +#define MASK_CLASS_TAG (((Eo_Id) 1UL) << (CLASS_TAG_SHIFT)) + +#define EO_ENTRIES_STEP 512 +//#define EO_ENTRY_LAST SIZE_MAX +#define EO_ENTRY_NULL ((uintptr_t)0) + + +typedef union +{ + struct { + _Eo_Object *ptr; + unsigned int generation; + } data; + + struct { + uintptr_t null; + size_t next; + } meta; +} Eo_Id_Entry; + +typedef struct +{ + struct { + Eo_Id id; + _Eo_Object *object; + const Eo *isa_id; + const Efl_Class *klass; + Eina_Bool isa; + } cache; + + Eo_Id_Entry *entries; + size_t count; + size_t next; + unsigned int generation; + + /* Optional */ + Eina_Lock obj_lock; + Eina_Bool shared; +} Eo_Id_Table; + +typedef struct +{ + Eo_Id_Table *tables[4]; + int local_domain; + unsigned int stack_top; + unsigned char domain_stack[256 - (sizeof(void *) * 4) - (2 * sizeof(unsigned int))]; +} Eo_Id_Data; + + + +extern Eo_Id_Data *_eo_table_data_shared; +extern Eo_Id_Table *_eo_table_data_shared_data; + + +extern Eo_Id_Data _eo_main_id_data; +extern Eo_Id_Table _eo_main_id_table; + +extern Eo_Id_Data *_eo_id_data; + +static inline void +_eo_id_entries_setup(Eo_Id_Entry *ptr, + size_t count, + size_t start_index) +{ + const size_t end = count + start_index; + for (size_t i = start_index; i < end; i++) + { + ptr[i].meta.null = EO_ENTRY_NULL; + ptr[i].meta.next = i + 1; + } +// ptr[end - 1].meta.null = EO_ENTRY_NULL; +// ptr[end - 1].meta.next = EO_ENTRY_LAST; +} + +static inline Eina_Bool +_eo_id_table_setup(Eo_Id_Table *table) +{ + /* Allocate a first bunch of entries */ + table->entries = malloc(sizeof(Eo_Id_Entry) * EO_ENTRIES_STEP); + if (EINA_UNLIKELY(! table->entries)) return EINA_FALSE; + table->count = EO_ENTRIES_STEP; + table->next = 0; + + _eo_id_entries_setup(table->entries, table->count, 0); + + return EINA_TRUE; +} + +static inline Eo_Id_Table * +_eo_id_table_new(Efl_Id_Domain domain) +{ + Eo_Id_Table *const table = calloc(1, sizeof(*table)); + if (EINA_UNLIKELY(! table)) return NULL; + + /* Initialize the array of entries */ + if (EINA_UNLIKELY(! _eo_id_table_setup(table))) + goto free_table; + + table->generation = rand() % MAX_GENERATIONS; + + if (domain == EFL_ID_DOMAIN_SHARED) + { + if (!eina_lock_recursive_new(&(table->obj_lock))) + goto free_entries; + table->shared = EINA_TRUE; + } + return table; + +free_entries: + free(table->entries); +free_table: + free(table); + return NULL; +} + +static inline void +_eo_id_table_clear(Eo_Id_Table *table) +{ + free(table->entries); + table->entries = NULL; + table->next = 0; + table->count = 0; + + if (table->shared) eina_lock_free(&(table->obj_lock)); +} + +static inline void +_eo_id_table_free(Eo_Id_Table *table) +{ + _eo_id_table_clear(table); + free(table); +} + + +static inline Eo_Id_Data * +_eo_main_id_data_new(void) +{ + Eo_Id_Data *const d = &_eo_main_id_data; + d->local_domain = EFL_ID_DOMAIN_MAIN; + d->domain_stack[d->stack_top] = EFL_ID_DOMAIN_MAIN; + d->tables[EFL_ID_DOMAIN_MAIN] = &_eo_main_id_table; + d->tables[EFL_ID_DOMAIN_SHARED] = _eo_table_data_shared_data; + + /* Init table */ + _eo_id_table_setup(&_eo_main_id_table); + + return d; +} + +static inline Eo_Id_Data * +_eo_id_data_new(Efl_Id_Domain domain) +{ + if (domain == EFL_ID_DOMAIN_MAIN) + return _eo_main_id_data_new(); + + Eo_Id_Data *const data = calloc(1, sizeof(Eo_Id_Data)); + if (EINA_UNLIKELY(! data)) return NULL; + + data->local_domain = domain; + data->domain_stack[data->stack_top] = data->local_domain; + data->tables[data->local_domain] = + _eo_id_table_new(data->local_domain); + if (domain != EFL_ID_DOMAIN_SHARED) + data->tables[EFL_ID_DOMAIN_SHARED] = _eo_table_data_shared_data; + return data; +} + +static inline Eo_Id_Data * +_eo_id_data_get(void) +{ + return _eo_id_data; +} + +static inline Eo_Id_Table * +_eo_current_table_get(Eo_Id_Data *data) +{ + return data->tables[data->domain_stack[data->stack_top]]; +} + +static inline Eo_Id_Table * +_eo_id_data_table_get(Eo_Id_Data *data, Efl_Id_Domain domain) +{ + return data->tables[domain]; +} + +static inline Eina_Bool +_eo_id_domain_compatible(const Eo *o1, const Eo *o2) +{ + Efl_Id_Domain domain1 = ((Eo_Id)o1 >> SHIFT_DOMAIN) & MASK_DOMAIN; + Efl_Id_Domain domain2 = ((Eo_Id)o2 >> SHIFT_DOMAIN) & MASK_DOMAIN; + if (domain1 == domain2) return EINA_TRUE; + ERR("Object %p and %p are not compatible. Domain %i and %i do not match", + o1, o2, domain1, domain2); + return EINA_FALSE; +} + +static inline void +_eo_obj_pointer_done(const Eo_Id obj_id) +{ + Efl_Id_Domain domain = (obj_id >> SHIFT_DOMAIN) & MASK_DOMAIN; + if (EINA_LIKELY(domain != EFL_ID_DOMAIN_SHARED)) return; + eina_lock_release(&(_eo_table_data_shared_data->obj_lock)); +} + +////////////////////////////////////////////////////////////////////////// + + +/* Macro used to compose an Eo id */ +#define EO_COMPOSE_ID(ENTRY, DOMAIN, GENERATION) \ + (((Eo_Id) 0x1 << REF_TAG_SHIFT) | \ + (((Eo_Id)DOMAIN & MASK_DOMAIN) << SHIFT_DOMAIN) | \ + (((Eo_Id)ENTRY & MASK_ENTRY_ID) << SHIFT_ENTRY_ID) | \ + ((Eo_Id)GENERATION & MASK_GENERATIONS)) + +/* Macro to extract from an Eo id the indexes of the tables */ +#define EO_DECOMPOSE_ID(ID, ENTRY, GENERATION) \ + ENTRY = (ID >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID; \ + GENERATION = ID & MASK_GENERATIONS; + + +static inline Eo_Id_Entry * +_eo_id_table_next_entry_get(Eo_Id_Table *table, + size_t *idx_out) +{ + /* The table is saturated with Eo IDs. Give it more room. */ + if (EINA_UNLIKELY(table->next == table->count)) + { + const size_t new_count = table->count + EO_ENTRIES_STEP; + // XXX Unlikely to overflow. + Eo_Id_Entry *const tmp = realloc(table->entries, new_count * sizeof(Eo_Id_Entry)); + if (EINA_UNLIKELY(! tmp)) + { + CRI("Failed to reallocate %zu elements", new_count); + return NULL; + } + + _eo_id_entries_setup(tmp, EO_ENTRIES_STEP, table->count); + + table->entries = tmp; + table->count = new_count; + } + else if (EINA_UNLIKELY(table->next > table->count)) + { + CRI("Invalid"); + return NULL; + } + + *idx_out = table->next; + Eo_Id_Entry *const entry = &(table->entries[table->next]); + if (EINA_UNLIKELY(entry->meta.null != EO_ENTRY_NULL)) + { + CRI("Boom. Eo is broken. Cell %zu is not free, but was expected to be...", *idx_out); + return NULL; + } + table->next = entry->meta.next; + + return entry; +} + +static inline void +_eo_id_table_entry_release(Eo_Id_Table *table, + size_t index) +{ + Eo_Id_Entry *const entry = &(table->entries[index]); + entry->meta.null = EO_ENTRY_NULL; /* This will annihilate the contents of ptr */ + entry->meta.next = table->next; + table->next = index; +} + +static inline Eo_Id +_eo_id_allocate(const _Eo_Object *obj, const Eo *parent_id) +{ + Eo_Id_Table *table; + Eo_Id id = 0; + + + Eo_Id_Data *const data = _eo_id_data_get(); + if (parent_id) + { + const Efl_Id_Domain domain = ((Eo_Id)parent_id >> SHIFT_DOMAIN) & MASK_DOMAIN; + table = _eo_id_data_table_get(data, domain); + } + else table = _eo_current_table_get(data); + if (EINA_UNLIKELY(!table)) return 0; + + + const Eo_Id domain = (table->shared) + ? EFL_ID_DOMAIN_SHARED + : data->domain_stack[data->stack_top]; + + if (EINA_UNLIKELY(! table->shared)) + eina_lock_take(&(_eo_table_data_shared_data->obj_lock)); + + + size_t idx; + Eo_Id_Entry *const entry = _eo_id_table_next_entry_get(table, &idx); + if (EINA_UNLIKELY(! entry)) goto fail; + + /* [1;max-1] thus we never generate an Eo_Id equal to 0 */ + table->generation++; + if (table->generation >= MAX_GENERATIONS) table->generation = 1; + /* Fill the entry and return it's Eo Id */ + entry->data.ptr = (_Eo_Object *)obj; + entry->data.generation = table->generation; + id = EO_COMPOSE_ID(idx, domain, entry->data.generation); + + +fail: + if (EINA_UNLIKELY(! table->shared)) + eina_lock_release(&(_eo_table_data_shared_data->obj_lock)); + + return id; +} + +static inline void +_eo_id_release(Eo_Id id) +{ + const Efl_Id_Domain domain = (id >> SHIFT_DOMAIN) & MASK_DOMAIN; + Eo_Id_Data *const data = _eo_id_data_get(); + Eo_Id_Table *const table = _eo_id_data_table_get(data, domain); + if (EINA_UNLIKELY(! table)) return; + + size_t entry_id; + unsigned int generation; + EO_DECOMPOSE_ID(id, entry_id, generation); + + if (EINA_UNLIKELY(domain == EFL_ID_DOMAIN_SHARED)) + eina_lock_take(&(_eo_table_data_shared_data->obj_lock)); + + /* If the entry index is out of bounds, that sucks... We never "ungrow" + * so this is definitely pure garbage. */ + if (EINA_UNLIKELY(entry_id >= table->count)) + { + ERR("Invalid entry id %zu >= %zu", entry_id, table->count); + goto fail; + } + + /* We are now sure that the object MAY have been allocated. At least we + * won't segfault trying to access it. */ + const Eo_Id_Entry *const entry = &(table->entries[entry_id]); + + /* If the entry has its 'null' field set to 0, it is highly probable that + * the object has already been freed. */ + if (EINA_UNLIKELY(entry->meta.null == EO_ENTRY_NULL)) + { + ERR("meta is already null"); + goto fail; + } + + /* If the generation count mismatch, the pointer is garbage */ + if (EINA_UNLIKELY(entry->data.generation != generation)) + { + ERR("ID: %p. invalid generation count: %u vs %u", (void*)id,entry->data.generation, generation); + goto fail; + } + + /* At this point we are almost sure that the object IS valid. We can release + * the Eo Id. */ + _eo_id_table_entry_release(table, entry_id); + + /* If we destroyed the ID that was in the table cache wipe out the cache */ + if (table->cache.id == id) + { + table->cache.id = 0; + table->cache.object = NULL; + } + if ((Eo_Id)table->cache.isa_id == id) + { + table->cache.isa_id = NULL; + table->cache.klass = NULL; + table->cache.isa = EINA_FALSE; + } + + if (EINA_UNLIKELY(domain == EFL_ID_DOMAIN_SHARED)) + eina_lock_release(&(_eo_table_data_shared_data->obj_lock)); + return; + +fail: + if (EINA_UNLIKELY(domain == EFL_ID_DOMAIN_SHARED)) + eina_lock_release(&(_eo_table_data_shared_data->obj_lock)); + ERR("obj_id %p is not pointing to a valid object. Maybe it has already been freed.", (void *)id); +} + + +#ifdef EFL_DEBUG +static inline void +_eo_print(const Eo_Id_Table *table) +{ + unsigned int object = 0; + for (size_t i = 0; i < table->count; i++) + { + const Eo_Id_Entry *const entry = &(table->entries[i]); + if (entry->meta.null != EO_ENTRY_NULL) + { + printf("%u[%zu]: %p -> (%u)\n", + object, i, entry->data.ptr, entry->data.generation); + object++; + } + } +} +#endif |