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)
downloadefl-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.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:
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