forked from enlightenment/efl
Revert "Revert eo vtale rework..."
This reverts commit efb15f510c
.
The error that was causing this was in ector, and is fixed with the
previous commit.
This commit is contained in:
parent
6934a9623e
commit
9f5ab4dea9
566
src/lib/eo/eo.c
566
src/lib/eo/eo.c
|
@ -90,7 +90,6 @@ static _Efl_Class **_eo_classes = NULL;
|
|||
static Eo_Id _eo_classes_last_id = 0;
|
||||
static Eo_Id _eo_classes_alloc = 0;
|
||||
static int _efl_object_init_count = 0;
|
||||
static Efl_Object_Op _eo_ops_last_id = 0;
|
||||
static Eina_Hash *_ops_storage = NULL;
|
||||
static Eina_Spinlock _ops_storage_lock;
|
||||
|
||||
|
@ -104,7 +103,6 @@ static void _eo_condtor_reset(_Eo_Object *obj);
|
|||
static inline void *_efl_data_scope_get(const _Eo_Object *obj, const _Efl_Class *klass);
|
||||
static inline void *_efl_data_xref_internal(const char *file, int line, _Eo_Object *obj, const _Efl_Class *klass, const _Eo_Object *ref_obj);
|
||||
static inline void _efl_data_xunref_internal(_Eo_Object *obj, void *data, const _Eo_Object *ref_obj);
|
||||
static void _vtable_init(Eo_Vtable *vtable, size_t size);
|
||||
|
||||
static inline Efl_Object_Op _efl_object_api_op_id_get_internal(const void *api_func);
|
||||
|
||||
|
@ -120,96 +118,190 @@ static inline Efl_Object_Op _efl_object_api_op_id_get_internal(const void *api_f
|
|||
(_eo_classes[_UNMASK_ID(id) - 1]) : NULL); \
|
||||
})
|
||||
|
||||
static inline void
|
||||
_vtable_chain2_unref(Dich_Chain2 *chain)
|
||||
#define EFL_OBJECT_OP_CLASS_PART(op) op >> 16
|
||||
#define EFL_OBJECT_OP_FUNC_PART(op) op & 0xffff
|
||||
#define EFL_OBJECT_OP_CREATE_OP_ID(class_id, func_id) ((unsigned short)class_id)<<16|((unsigned short)func_id&0xffff)
|
||||
|
||||
static const _Efl_Class *
|
||||
_eo_op_class_get(Efl_Object_Op op)
|
||||
{
|
||||
if (--(chain->refcount) == 0)
|
||||
{
|
||||
free(chain);
|
||||
}
|
||||
short class_id = EFL_OBJECT_OP_CLASS_PART(op);
|
||||
return _eo_classes[class_id];
|
||||
}
|
||||
#if defined(DEBUG_VTABLE_ALLOCATION)
|
||||
static int _allocated_memory = 0;
|
||||
|
||||
static inline void*
|
||||
_vtable_alloc(unsigned long n, size_t elem)
|
||||
{
|
||||
_allocated_memory += n*elem;
|
||||
return calloc(n, elem);
|
||||
}
|
||||
#else
|
||||
static inline void*
|
||||
_vtable_alloc(unsigned long n, size_t elem)
|
||||
{
|
||||
return calloc(n, elem);
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* This inits the vtable wit hthe current size of allocated tables
|
||||
*/
|
||||
static void
|
||||
_vtable_init(Eo_Vtable *vtable)
|
||||
{
|
||||
//we assume here that _eo_classes_last_id was called before
|
||||
vtable->size = _eo_classes_last_id;
|
||||
vtable->chain = _vtable_alloc(vtable->size, sizeof(Eo_Vtable_Node));
|
||||
}
|
||||
|
||||
static inline void
|
||||
_vtable_chain_alloc(Dich_Chain1 *chain1)
|
||||
/**
|
||||
* This removes all nodes from the klass that are copied from mro
|
||||
*/
|
||||
static void
|
||||
_vtable_mro_free(const _Efl_Class *klass)
|
||||
{
|
||||
chain1->chain2 = calloc(1, sizeof(*(chain1->chain2)));
|
||||
chain1->chain2->refcount = 1;
|
||||
}
|
||||
const _Efl_Class **mro_itr = klass->mro;
|
||||
const Eo_Vtable *vtable = &klass->vtable;
|
||||
|
||||
static inline void _vtable_chain_write_prepare(Dich_Chain1 *dst);
|
||||
|
||||
static inline void
|
||||
_vtable_chain_merge(Dich_Chain1 *dst, const Dich_Chain1 *src)
|
||||
{
|
||||
size_t j;
|
||||
const op_type_funcs *sf = src->chain2->funcs;
|
||||
op_type_funcs *df = dst->chain2->funcs;
|
||||
|
||||
if (df == sf)
|
||||
for ( ; *mro_itr ; mro_itr++)
|
||||
{
|
||||
/* Skip if the chain is the same. */
|
||||
return;
|
||||
}
|
||||
|
||||
for (j = 0 ; j < DICH_CHAIN_LAST_SIZE ; j++, df++, sf++)
|
||||
{
|
||||
if (sf->func && memcmp(df, sf, sizeof(*df)))
|
||||
const Eo_Vtable *mro_vtable = &(*mro_itr)->vtable;
|
||||
for (int i = 0; i < mro_vtable->size; ++i)
|
||||
{
|
||||
_vtable_chain_write_prepare(dst);
|
||||
df = dst->chain2->funcs + j;
|
||||
memcpy(df, sf, sizeof(*df));
|
||||
if (mro_vtable->chain[i].funcs == vtable->chain[i].funcs)
|
||||
vtable->chain[i].funcs = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_vtable_chain_write_prepare(Dich_Chain1 *dst)
|
||||
static void
|
||||
_vtable_free(Eo_Vtable *vtable, const Eo_Vtable *root)
|
||||
{
|
||||
if (!dst->chain2)
|
||||
if (root)
|
||||
{
|
||||
_vtable_chain_alloc(dst);
|
||||
return;
|
||||
}
|
||||
else if (dst->chain2->refcount == 1)
|
||||
{
|
||||
/* We own it, no need to duplicate */
|
||||
return;
|
||||
EINA_SAFETY_ON_FALSE_RETURN(vtable->size == root->size);
|
||||
}
|
||||
|
||||
Dich_Chain1 old;
|
||||
old.chain2 = dst->chain2;
|
||||
|
||||
_vtable_chain_alloc(dst);
|
||||
_vtable_chain_merge(dst, &old);
|
||||
|
||||
_vtable_chain2_unref(old.chain2);
|
||||
}
|
||||
|
||||
static inline void
|
||||
_vtable_chain_copy_ref(Dich_Chain1 *dst, const Dich_Chain1 *src)
|
||||
{
|
||||
if (dst->chain2)
|
||||
for (int i = 0; i < vtable->size; ++i)
|
||||
{
|
||||
_vtable_chain_merge(dst, src);
|
||||
}
|
||||
else
|
||||
{
|
||||
dst->chain2 = src->chain2;
|
||||
dst->chain2->refcount++;
|
||||
}
|
||||
}
|
||||
if (root && root->chain[i].funcs == vtable->chain[i].funcs)
|
||||
vtable->chain[i].count = 0;
|
||||
|
||||
static inline void
|
||||
_vtable_copy_all(Eo_Vtable *dst, const Eo_Vtable *src)
|
||||
{
|
||||
Efl_Object_Op i;
|
||||
const Dich_Chain1 *sc1 = src->chain;
|
||||
Dich_Chain1 *dc1 = dst->chain;
|
||||
for (i = 0 ; i < src->size ; i++, sc1++, dc1++)
|
||||
{
|
||||
if (sc1->chain2)
|
||||
if (vtable->chain[i].count)
|
||||
{
|
||||
_vtable_chain_copy_ref(dc1, sc1);
|
||||
free(vtable->chain[i].funcs);
|
||||
}
|
||||
}
|
||||
free(vtable->chain);
|
||||
}
|
||||
|
||||
/**
|
||||
* This takes over all set chains of the src to dest.
|
||||
* This should only be called on Eo_Vtables, which are initialized with this value.
|
||||
* Previous setted values are going to be overwritten.
|
||||
*/
|
||||
static void
|
||||
_vtable_take_over(Eo_Vtable *dest, const Eo_Vtable *src)
|
||||
{
|
||||
for (int i = 0; i < src->size; ++i)
|
||||
{
|
||||
if (src->chain[i].funcs)
|
||||
{
|
||||
dest->chain[i] = src->chain[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fills the node of the passed class id with a empty none NULL pointer.
|
||||
* This is used to indicate that a specific node has a normal 0 size, but is set.
|
||||
*/
|
||||
static void
|
||||
_vtable_insert_empty_funcs(Eo_Vtable *vtable, unsigned short class_id)
|
||||
{
|
||||
vtable->chain[class_id].funcs = (void*)0x1010101;
|
||||
vtable->chain[class_id].count = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* duplicate the source node, and write the duplicated values to the destination
|
||||
* No logical changes are applied to src.
|
||||
*/
|
||||
static void
|
||||
_vtable_copy_node(Eo_Vtable_Node *dest, const Eo_Vtable_Node *src)
|
||||
{
|
||||
dest->count = src->count;
|
||||
dest->funcs = _vtable_alloc(sizeof(op_type_funcs), src->count);
|
||||
memcpy(dest->funcs, src->funcs, sizeof(op_type_funcs) * src->count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a node with a empty funcs array of the passed length
|
||||
*/
|
||||
static void
|
||||
_vtable_prepare_empty_node(Eo_Vtable *dest, unsigned int length, unsigned int class_id)
|
||||
{
|
||||
dest->chain[class_id].count = length;
|
||||
dest->chain[class_id].funcs = _vtable_alloc(sizeof(op_type_funcs), dest->chain[class_id].count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy all setted APIs from src to dest.
|
||||
* Already set function slots are going to be replaced.
|
||||
*/
|
||||
static void
|
||||
_vtable_merge_defined_api(Eo_Vtable *dest, const Eo_Vtable *src, Eina_Bool *hitmap)
|
||||
{
|
||||
for (unsigned int i = 0; i < src->size; ++i)
|
||||
{
|
||||
//if there is a source node evalulate if we need to copy it
|
||||
if (src->chain[i].funcs)
|
||||
{
|
||||
if (!dest->chain[i].funcs)
|
||||
{
|
||||
dest->chain[i] = src->chain[i];
|
||||
EINA_SAFETY_ON_FALSE_RETURN(hitmap[i] == EINA_FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!hitmap[i])
|
||||
{
|
||||
const Eo_Vtable_Node node = dest->chain[i];
|
||||
_vtable_copy_node(&dest->chain[i], &node); //we copy what we have, and overwrite in the later for loop
|
||||
hitmap[i] = EINA_TRUE;
|
||||
}
|
||||
for (int j = 0; j < src->chain[i].count; ++j)
|
||||
{
|
||||
if (src->chain[i].funcs[j].func)
|
||||
dest->chain[i].funcs[j] = src->chain[i].funcs[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that all set nodes from src are also set on dest.
|
||||
* No real values are copied, the newly taken or allocated slots will be empty.
|
||||
*/
|
||||
static void
|
||||
_vtable_merge_empty(Eo_Vtable *dest, const Eo_Vtable *src, Eina_Bool *hitmap)
|
||||
{
|
||||
for (unsigned int i = 0; i < src->size; ++i)
|
||||
{
|
||||
if (src->chain[i].funcs && !dest->chain[i].funcs)
|
||||
{
|
||||
if (!src->chain[i].count)
|
||||
{
|
||||
dest->chain[i].funcs = src->chain[i].funcs;
|
||||
dest->chain[i].count = src->chain[i].count;
|
||||
}
|
||||
else
|
||||
{
|
||||
_vtable_prepare_empty_node(dest, src->chain[i].count, i);
|
||||
hitmap[i] = EINA_TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -217,37 +309,15 @@ _vtable_copy_all(Eo_Vtable *dst, const Eo_Vtable *src)
|
|||
static inline const op_type_funcs *
|
||||
_vtable_func_get(const Eo_Vtable *vtable, Efl_Object_Op op)
|
||||
{
|
||||
size_t idx1 = DICH_CHAIN1(op);
|
||||
if (EINA_UNLIKELY(idx1 >= vtable->size))
|
||||
return NULL;
|
||||
Dich_Chain1 *chain1 = &vtable->chain[idx1];
|
||||
if (EINA_UNLIKELY(!chain1->chain2))
|
||||
return NULL;
|
||||
return &chain1->chain2->funcs[DICH_CHAIN_LAST(op)];
|
||||
}
|
||||
unsigned short class_id = EFL_OBJECT_OP_CLASS_PART(op);
|
||||
unsigned short func_id = EFL_OBJECT_OP_FUNC_PART(op);
|
||||
|
||||
/* XXX: Only used for a debug message below. Doesn't matter that it's slow. */
|
||||
static const _Efl_Class *
|
||||
_eo_op_class_get(Efl_Object_Op op)
|
||||
{
|
||||
_Efl_Class **itr = _eo_classes;
|
||||
int mid, max, min;
|
||||
if (EINA_UNLIKELY(vtable->size <= class_id))
|
||||
return NULL;
|
||||
if (EINA_UNLIKELY(vtable->chain[class_id].count <= func_id))
|
||||
return NULL;
|
||||
|
||||
min = 0;
|
||||
max = _eo_classes_last_id - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
mid = (min + max) / 2;
|
||||
|
||||
if (itr[mid]->base_id + itr[mid]->ops_count < op)
|
||||
min = mid + 1;
|
||||
else if (itr[mid]->base_id > op)
|
||||
max = mid - 1;
|
||||
else
|
||||
return itr[mid];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return &vtable->chain[class_id].funcs[func_id];
|
||||
}
|
||||
|
||||
static inline Eina_Bool
|
||||
|
@ -256,24 +326,30 @@ _vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass,
|
|||
Eo_Op_Func_Type func, Eina_Bool allow_same_override)
|
||||
{
|
||||
op_type_funcs *fsrc;
|
||||
size_t idx1 = DICH_CHAIN1(op);
|
||||
Dich_Chain1 *chain1;
|
||||
unsigned short class_id = EFL_OBJECT_OP_CLASS_PART(op);
|
||||
unsigned short func_id = EFL_OBJECT_OP_FUNC_PART(op);
|
||||
Eo_Vtable_Node *hirachy_node = NULL;
|
||||
Eo_Vtable_Node *node = NULL;
|
||||
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(idx1 < vtable->size, EINA_FALSE);
|
||||
chain1 = &vtable->chain[idx1];
|
||||
_vtable_chain_write_prepare(chain1);
|
||||
fsrc = &chain1->chain2->funcs[DICH_CHAIN_LAST(op)];
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(vtable->size >= class_id, EINA_FALSE);
|
||||
|
||||
if (klass->parent && klass->parent->vtable.size > class_id)
|
||||
hirachy_node = &klass->parent->vtable.chain[class_id];
|
||||
if (hierarchy_klass)
|
||||
hirachy_node = &hierarchy_klass->vtable.chain[class_id];
|
||||
node = &vtable->chain[class_id];
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(node->funcs, EINA_FALSE);
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL(node->count >= func_id, EINA_FALSE);
|
||||
fsrc = &node->funcs[func_id];
|
||||
|
||||
if (hierarchy_klass && !func)
|
||||
{
|
||||
if (!func)
|
||||
{
|
||||
op_type_funcs *fsrc_orig;
|
||||
Dich_Chain1 *chain1_orig;
|
||||
|
||||
chain1_orig = &hierarchy_klass->vtable.chain[idx1];
|
||||
fsrc_orig = &chain1_orig->chain2->funcs[DICH_CHAIN_LAST(op)];
|
||||
func = fsrc_orig->func;
|
||||
klass = fsrc_orig->src;
|
||||
op_type_funcs funcs = hirachy_node->funcs[func_id];
|
||||
klass = funcs.src;
|
||||
func = funcs.func;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -287,27 +363,12 @@ _vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass,
|
|||
}
|
||||
}
|
||||
|
||||
fsrc->func = func;
|
||||
fsrc->src = klass;
|
||||
fsrc->func = func;
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
_vtable_func_clean_all(Eo_Vtable *vtable)
|
||||
{
|
||||
size_t i;
|
||||
Dich_Chain1 *chain1 = vtable->chain;
|
||||
|
||||
for (i = 0 ; i < vtable->size ; i++, chain1++)
|
||||
{
|
||||
if (chain1->chain2)
|
||||
_vtable_chain2_unref(chain1->chain2);
|
||||
}
|
||||
free(vtable->chain);
|
||||
vtable->chain = NULL;
|
||||
}
|
||||
|
||||
/* END OF DICH */
|
||||
|
||||
#define _EO_ID_GET(Id) ((Eo_Id) (Id))
|
||||
|
@ -478,7 +539,7 @@ _efl_object_call_resolve(Eo *eo_id, const char *func_name, Efl_Object_Op_Call_Da
|
|||
|
||||
obj = _obj;
|
||||
klass = _obj->klass;
|
||||
vtable = EO_VTABLE(obj);
|
||||
vtable = EO_VTABLE2(obj);
|
||||
if (EINA_UNLIKELY(_obj->cur_klass != NULL))
|
||||
{
|
||||
// YES this is a goto with a label to return. this is a
|
||||
|
@ -544,7 +605,7 @@ end:
|
|||
EO_OBJ_POINTER_PROXY(emb_obj_id, emb_obj);
|
||||
if (EINA_UNLIKELY(!emb_obj)) continue;
|
||||
|
||||
func = _vtable_func_get(EO_VTABLE(emb_obj), op);
|
||||
func = _vtable_func_get(&emb_obj->klass->vtable, op);
|
||||
if (func == NULL) goto composite_continue;
|
||||
|
||||
if (EINA_LIKELY(func->func && func->src))
|
||||
|
@ -727,23 +788,25 @@ _efl_object_op_api_id_get(const void *api_func, const Eo *eo_obj, const char *ap
|
|||
/* klass is the klass we are working on. hierarchy_klass is the class whe should
|
||||
* use when validating. */
|
||||
static Eina_Bool
|
||||
_eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Class *hierarchy_klass, const _Efl_Class *klass, Efl_Object_Op id_offset, Eina_Bool override_only)
|
||||
_eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Class *hierarchy_klass, const _Efl_Class *klass, Eina_Bool override_only, unsigned int class_id, Eina_Bool *hitmap)
|
||||
{
|
||||
unsigned int i, j;
|
||||
Efl_Object_Op op_id;
|
||||
unsigned int number_of_new_functions = 0;
|
||||
const Efl_Op_Description *op_desc;
|
||||
const Efl_Op_Description *op_descs;
|
||||
const _Efl_Class *override_class;
|
||||
const void **api_funcs;
|
||||
Eina_Bool check_equal;
|
||||
|
||||
op_id = hierarchy_klass->base_id + id_offset;
|
||||
op_descs = ops->descs;
|
||||
override_class = override_only ? hierarchy_klass : NULL;
|
||||
|
||||
DBG("Set functions for class '%s':%p", klass->desc->name, klass);
|
||||
|
||||
if (!op_descs || !ops->count) return EINA_TRUE;
|
||||
if (!override_only)
|
||||
_vtable_insert_empty_funcs(vtable, class_id);
|
||||
if (!op_descs || !ops->count)
|
||||
return EINA_TRUE;
|
||||
|
||||
#ifdef EO_DEBUG
|
||||
check_equal = EINA_TRUE;
|
||||
|
@ -776,43 +839,61 @@ _eo_class_funcs_set(Eo_Vtable *vtable, const Efl_Object_Ops *ops, const _Efl_Cla
|
|||
|
||||
api_funcs[i] = op_desc->api_func;
|
||||
}
|
||||
if (_efl_object_api_op_id_get_internal(op_desc->api_func) == EFL_NOOP)
|
||||
{
|
||||
number_of_new_functions ++;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
|
||||
if (!override_only)
|
||||
{
|
||||
Efl_Object_Op op = EFL_NOOP;
|
||||
//Before setting any real functions, allocate the node that will contain all the functions
|
||||
_vtable_prepare_empty_node(vtable, number_of_new_functions, class_id);
|
||||
hitmap[class_id] = EINA_TRUE;
|
||||
}
|
||||
|
||||
for (i = 0, j = 0, op_desc = op_descs; i < ops->count; i++, op_desc++)
|
||||
{
|
||||
Efl_Object_Op op2 = EFL_NOOP;
|
||||
short op2_class_id;
|
||||
|
||||
/* Get the opid for the function. */
|
||||
op = _efl_object_api_op_id_get_internal(op_desc->api_func);
|
||||
op2 = _efl_object_api_op_id_get_internal(op_desc->api_func);
|
||||
|
||||
if (op == EFL_NOOP)
|
||||
if (op2 == EFL_NOOP)
|
||||
{
|
||||
//functions that do not have a op yet, are considered to be belonging to this class
|
||||
if (override_only)
|
||||
{
|
||||
ERR("Class '%s': Tried overriding a previously undefined function.", klass->desc->name);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
op = op_id;
|
||||
op2 = EFL_OBJECT_OP_CREATE_OP_ID(class_id, j);
|
||||
eina_spinlock_take(&_ops_storage_lock);
|
||||
#ifndef _WIN32
|
||||
eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op);
|
||||
eina_hash_add(_ops_storage, &op_desc->api_func, (void *) (uintptr_t) op2);
|
||||
#else
|
||||
eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op);
|
||||
eina_hash_add(_ops_storage, op_desc->api_func, (void *) (uintptr_t) op2);
|
||||
#endif
|
||||
eina_spinlock_release(&_ops_storage_lock);
|
||||
|
||||
op_id++;
|
||||
j ++;
|
||||
}
|
||||
|
||||
#ifdef EO_DEBUG
|
||||
DBG("%p->%p '%s'", op_desc->api_func, op_desc->func, _eo_op_desc_name_get(op_desc));
|
||||
#endif
|
||||
|
||||
if (!_vtable_func_set(vtable, klass, override_class, op, op_desc->func, EINA_TRUE))
|
||||
op2_class_id = EFL_OBJECT_OP_CLASS_PART(op2);
|
||||
//in case we are having a function overwrite for a specific type, copy the relevant vtable
|
||||
if (!hitmap[op2_class_id])
|
||||
{
|
||||
const Eo_Vtable_Node node = vtable->chain[op2_class_id];
|
||||
_vtable_copy_node(&vtable->chain[op2_class_id], &node);
|
||||
hitmap[op2_class_id] = EINA_TRUE;
|
||||
}
|
||||
if (!_vtable_func_set(vtable, klass, override_class, op2, op_desc->func, EINA_TRUE))
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
|
@ -821,6 +902,7 @@ efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_
|
|||
{
|
||||
EO_CLASS_POINTER_GOTO(klass_id, klass, err_klass);
|
||||
Efl_Object_Ops empty_ops = { 0 };
|
||||
Eina_Bool *hitmap;
|
||||
|
||||
// not likely so use goto to alleviate l1 instruction cache of rare code
|
||||
if (klass->functions_set) goto err_funcs;
|
||||
|
@ -832,23 +914,75 @@ efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_
|
|||
|
||||
klass->ops_count = object_ops->count;
|
||||
|
||||
klass->base_id = _eo_ops_last_id;
|
||||
_eo_ops_last_id += klass->ops_count + 1;
|
||||
klass->class_id = _UNMASK_ID(klass->header.id) - 1;
|
||||
|
||||
_vtable_init(&klass->vtable, DICH_CHAIN1(_eo_ops_last_id) + 1);
|
||||
_vtable_init(&klass->vtable);
|
||||
|
||||
/* Flatten the function array */
|
||||
hitmap = alloca(klass->vtable.size);
|
||||
memset(hitmap, 0, klass->vtable.size);
|
||||
/* Merge in all required vtable entries */
|
||||
{
|
||||
const _Efl_Class **mro_itr = klass->mro;
|
||||
for ( ; *mro_itr ; mro_itr++) ;
|
||||
|
||||
/* Skip ourselves. */
|
||||
/* take over everything from the parent */
|
||||
if (klass->parent)
|
||||
{
|
||||
_vtable_take_over(&klass->vtable, &klass->parent->vtable);
|
||||
}
|
||||
/*
|
||||
* - jump to the mro entry containing the parent
|
||||
* - everything further from the parent to the next elements is already
|
||||
* represented in the vtable of the parent.
|
||||
*/
|
||||
for ( ; *mro_itr ; mro_itr++)
|
||||
{
|
||||
if (*mro_itr == klass->parent)
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* merge in all the APIs that are extended in the current klass for this first time.
|
||||
* That means, they are not extended anywhere from the parent further up.
|
||||
*/
|
||||
for ( mro_itr-- ; mro_itr > klass->mro ; mro_itr--)
|
||||
_vtable_copy_all(&klass->vtable, &(*mro_itr)->vtable);
|
||||
{
|
||||
_vtable_merge_defined_api(&klass->vtable, &(*mro_itr)->vtable, hitmap);
|
||||
}
|
||||
/*
|
||||
* add slots for the interfaces and mixins we are inheriting from
|
||||
*/
|
||||
for (int i = 0; klass->extensions[i]; i++)
|
||||
{
|
||||
const _Efl_Class *ext = klass->extensions[i];
|
||||
/*for all extensions of the class, ensure that *at least* empty vtables are available, so the efl_isa calls do succeed*/
|
||||
_vtable_merge_empty(&klass->vtable, &ext->vtable, hitmap);
|
||||
}
|
||||
}
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
return _eo_class_funcs_set(&klass->vtable, object_ops, klass, klass, 0, EINA_FALSE);
|
||||
for (i = 0; i < object_ops->count; i++)
|
||||
{
|
||||
Efl_Object_Op op = _efl_object_api_op_id_get_internal(object_ops->descs[i].api_func);
|
||||
if (op == EFL_NOOP) continue; //EFL_NOOP means that this function is not yet defined, this will be handled later
|
||||
short class_id = EFL_OBJECT_OP_CLASS_PART(op);
|
||||
if (klass->vtable.chain[class_id].count == 0)
|
||||
{
|
||||
const _Efl_Class *required_klass = _eo_classes[class_id];
|
||||
/* in case this type is not already inherited, error on everything that is not a mixin */
|
||||
if (klass->desc->type == EFL_CLASS_TYPE_MIXIN)
|
||||
{
|
||||
/* this is when a mixin implemets a regular api, we just prepare a empty node, the rest will be implemented later */
|
||||
_vtable_prepare_empty_node(&klass->vtable, required_klass->vtable.chain[class_id].count, class_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("There is an API implemented, whoms type is not part of this class. %s vs. %s", klass->desc->name, required_klass->desc->name);
|
||||
_vtable_take_over(&klass->vtable, &required_klass->vtable);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return _eo_class_funcs_set(&klass->vtable, object_ops, klass, klass, EINA_FALSE, klass->class_id, hitmap);
|
||||
err_funcs:
|
||||
ERR("Class %s already had its functions set..", klass->desc->name);
|
||||
return EINA_FALSE;
|
||||
|
@ -1098,8 +1232,8 @@ _eo_free(_Eo_Object *obj, Eina_Bool manual_free EINA_UNUSED)
|
|||
#endif
|
||||
if (_obj_is_override(obj))
|
||||
{
|
||||
_vtable_func_clean_all(obj->opt->vtable);
|
||||
eina_freeq_ptr_main_add(obj->opt->vtable, free, 0);
|
||||
if (obj->opt)
|
||||
_vtable_free(obj->opt->vtable, &obj->klass->vtable);
|
||||
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
|
||||
}
|
||||
|
||||
|
@ -1190,22 +1324,6 @@ err_obj:
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
_vtable_init(Eo_Vtable *vtable, size_t size)
|
||||
{
|
||||
vtable->size = size;
|
||||
vtable->chain = calloc(vtable->size, sizeof(*vtable->chain));
|
||||
}
|
||||
|
||||
static void
|
||||
_vtable_free(Eo_Vtable *vtable)
|
||||
{
|
||||
if (!vtable) return;
|
||||
_vtable_func_clean_all(vtable);
|
||||
eina_freeq_ptr_main_add(vtable, free, sizeof(*vtable));
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_eo_class_mro_has(const _Efl_Class *klass, const _Efl_Class *find)
|
||||
{
|
||||
|
@ -1360,8 +1478,8 @@ eo_class_free(_Efl_Class *klass)
|
|||
{
|
||||
if (klass->desc->class_destructor)
|
||||
klass->desc->class_destructor(_eo_class_id_get(klass));
|
||||
|
||||
_vtable_func_clean_all(&klass->vtable);
|
||||
_vtable_mro_free(klass);
|
||||
_vtable_free(&klass->vtable, NULL);
|
||||
}
|
||||
|
||||
EINA_TRASH_CLEAN(&klass->objects.trash, data)
|
||||
|
@ -1376,32 +1494,6 @@ eo_class_free(_Efl_Class *klass)
|
|||
eina_freeq_ptr_main_add(klass, free, 0);
|
||||
}
|
||||
|
||||
/* Not really called, just used for the ptr... */
|
||||
static void
|
||||
_eo_class_isa_func(Eo *eo_id EINA_UNUSED, void *class_data EINA_UNUSED)
|
||||
{
|
||||
/* Do nonthing. */
|
||||
}
|
||||
|
||||
static void
|
||||
_eo_class_isa_recursive_set(_Efl_Class *klass, const _Efl_Class *cur)
|
||||
{
|
||||
const _Efl_Class **extn_itr;
|
||||
|
||||
_vtable_func_set(&klass->vtable, klass, NULL, cur->base_id + cur->ops_count,
|
||||
_eo_class_isa_func, EINA_TRUE);
|
||||
|
||||
for (extn_itr = cur->extensions ; *extn_itr ; extn_itr++)
|
||||
{
|
||||
_eo_class_isa_recursive_set(klass, *extn_itr);
|
||||
}
|
||||
|
||||
if (cur->parent)
|
||||
{
|
||||
_eo_class_isa_recursive_set(klass, cur->parent);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_eo_classes_release(void)
|
||||
{
|
||||
|
@ -1710,12 +1802,6 @@ efl_class_new(const Efl_Class_Description *desc, const Efl_Class *parent_id, ...
|
|||
efl_class_functions_set(_eo_class_id_get(klass), NULL, NULL);
|
||||
}
|
||||
|
||||
/* Mark which classes we implement */
|
||||
if (klass->vtable.size)
|
||||
{
|
||||
_eo_class_isa_recursive_set(klass, klass);
|
||||
}
|
||||
|
||||
_eo_class_constructor(klass);
|
||||
|
||||
DBG("Finished building class '%s'", klass->desc->name);
|
||||
|
@ -1732,32 +1818,41 @@ efl_object_override(Eo *eo_id, const Efl_Object_Ops *ops)
|
|||
if (ops)
|
||||
{
|
||||
Eo_Vtable *vtable = obj->opt->vtable;
|
||||
//copy all the vtable nodes that we are going to change later on
|
||||
Eina_Bool *hitmap;
|
||||
|
||||
if (!vtable)
|
||||
{
|
||||
vtable = calloc(1, sizeof(*vtable));
|
||||
_vtable_init(vtable, obj->klass->vtable.size);
|
||||
_vtable_copy_all(vtable, &obj->klass->vtable);
|
||||
_vtable_init(vtable);
|
||||
_vtable_take_over(vtable, &obj->klass->vtable);
|
||||
}
|
||||
|
||||
if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, 0, EINA_TRUE))
|
||||
hitmap = alloca(vtable->size * sizeof(Eina_Bool));
|
||||
memset(hitmap, 0, vtable->size);
|
||||
|
||||
if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, EINA_TRUE, obj->klass->class_id, hitmap))
|
||||
{
|
||||
ERR("Failed to override functions for %s@%p. All previous "
|
||||
"overrides have been reset.", obj->klass->desc->name, eo_id);
|
||||
if (obj->opt->vtable == vtable)
|
||||
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
|
||||
{
|
||||
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
|
||||
}
|
||||
else
|
||||
_vtable_free(vtable);
|
||||
{
|
||||
_vtable_free(vtable, &obj->klass->vtable);
|
||||
}
|
||||
|
||||
goto err;
|
||||
}
|
||||
|
||||
EO_OPTIONAL_COW_SET(obj, vtable, vtable);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (obj->opt->vtable)
|
||||
{
|
||||
_vtable_free(obj->opt->vtable);
|
||||
_vtable_free(obj->opt->vtable, &obj->klass->vtable);
|
||||
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
|
||||
}
|
||||
}
|
||||
|
@ -1791,10 +1886,10 @@ efl_isa(const Eo *eo_id, const Efl_Class *klass_id)
|
|||
EO_CLASS_POINTER_GOTO(klass_id, klass, err_class);
|
||||
EO_CLASS_POINTER_GOTO(eo_id, lookinto, err_class0);
|
||||
|
||||
const op_type_funcs *func = _vtable_func_get
|
||||
(&lookinto->vtable, klass->base_id + klass->ops_count);
|
||||
if (EINA_UNLIKELY(lookinto->vtable.size <= klass->class_id))
|
||||
return EINA_FALSE;
|
||||
|
||||
return (func && (func->func == _eo_class_isa_func));;
|
||||
return !!lookinto->vtable.chain[klass->class_id].funcs;
|
||||
}
|
||||
|
||||
domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
|
||||
|
@ -1813,15 +1908,17 @@ efl_isa(const Eo *eo_id, const Efl_Class *klass_id)
|
|||
|
||||
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
|
||||
(EO_VTABLE(obj), klass->base_id + klass->ops_count);
|
||||
|
||||
const Eo_Vtable vtable = obj->klass->vtable;
|
||||
if (EINA_UNLIKELY(vtable.size <= klass->class_id))
|
||||
return EINA_FALSE;
|
||||
|
||||
isa = !!vtable.chain[klass->class_id].funcs;
|
||||
|
||||
// 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;
|
||||
// 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));
|
||||
tdata->cache.isa = isa;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1841,15 +1938,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
|
||||
(EO_VTABLE(obj), klass->base_id + klass->ops_count);
|
||||
if (EINA_UNLIKELY(obj->klass->vtable.size <= klass->class_id))
|
||||
return EINA_FALSE;
|
||||
|
||||
isa = !!obj->klass->vtable.chain[klass->class_id].funcs;
|
||||
|
||||
// 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;
|
||||
// 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));
|
||||
tdata->cache.isa = isa;
|
||||
EO_OBJ_DONE(eo_id);
|
||||
eina_lock_release(&(_eo_table_data_shared_data->obj_lock));
|
||||
}
|
||||
|
@ -2326,7 +2423,6 @@ efl_object_init(void)
|
|||
|
||||
_eo_classes = NULL;
|
||||
_eo_classes_last_id = EO_CLASS_IDS_FIRST - 1;
|
||||
_eo_ops_last_id = EFL_OBJECT_OP_IDS_FIRST;
|
||||
_eo_log_dom = eina_log_domain_register(log_dom, EINA_COLOR_LIGHTBLUE);
|
||||
if (_eo_log_dom < 0)
|
||||
{
|
||||
|
@ -2384,12 +2480,6 @@ efl_object_init(void)
|
|||
eina_tls_set(_eo_table_data, data);
|
||||
_efl_object_main_thread = eina_thread_self();
|
||||
|
||||
#ifdef EO_DEBUG
|
||||
/* Call it just for coverage purposes. Ugly I know, but I like it better than
|
||||
* casting everywhere else. */
|
||||
_eo_class_isa_func(NULL, NULL);
|
||||
#endif
|
||||
|
||||
efl_object_optional_cow =
|
||||
eina_cow_add("Efl Object Optional Data", sizeof(Efl_Object_Optional),
|
||||
64, &efl_object_optional_cow_default, EINA_TRUE);
|
||||
|
|
|
@ -2325,7 +2325,7 @@ _efl_object_event_callback_forwarder_del(Eo *obj, Efl_Object_Data *pd EINA_UNUSE
|
|||
dpd = efl_data_scope_safe_get(new_obj, EFL_OBJECT_CLASS);
|
||||
if (!dpd) return ;
|
||||
|
||||
ext = _efl_object_extension_need(dpd);
|
||||
ext = dpd->ext;
|
||||
if (!ext) return ;
|
||||
|
||||
EINA_LIST_FOREACH(eina_hash_find(ext->forwarders, desc), l, forwarder)
|
||||
|
|
|
@ -70,17 +70,14 @@ static inline void _eo_id_release(const Eo_Id obj_id);
|
|||
|
||||
void _eo_condtor_done(Eo *obj);
|
||||
|
||||
typedef struct _Dich_Chain1 Dich_Chain1;
|
||||
typedef struct _Eo_Vtable_Node Eo_Vtable_Node;
|
||||
|
||||
typedef struct _Eo_Vtable
|
||||
{
|
||||
Dich_Chain1 *chain;
|
||||
unsigned int size;
|
||||
Eo_Vtable_Node *chain;
|
||||
unsigned short size;
|
||||
} Eo_Vtable;
|
||||
|
||||
/* Clean the vtable. */
|
||||
void _vtable_func_clean_all(Eo_Vtable *vtable);
|
||||
|
||||
struct _Eo_Header
|
||||
{
|
||||
Eo_Id id;
|
||||
|
@ -88,7 +85,7 @@ struct _Eo_Header
|
|||
|
||||
struct _Efl_Object_Optional
|
||||
{
|
||||
Eo_Vtable *vtable;
|
||||
Eo_Vtable *vtable;
|
||||
Eina_List *composite_objects;
|
||||
Efl_Del_Intercept del_intercept;
|
||||
};
|
||||
|
@ -129,12 +126,6 @@ struct _Eo_Object
|
|||
Eina_Bool ownership_track:1;
|
||||
};
|
||||
|
||||
/* How we search and store the implementations in classes. */
|
||||
#define DICH_CHAIN_LAST_BITS 5
|
||||
#define DICH_CHAIN_LAST_SIZE (1 << DICH_CHAIN_LAST_BITS)
|
||||
#define DICH_CHAIN1(x) ((x) >> DICH_CHAIN_LAST_BITS)
|
||||
#define DICH_CHAIN_LAST(x) ((x) & ((1 << DICH_CHAIN_LAST_BITS) - 1))
|
||||
|
||||
extern Eina_Cow *efl_object_optional_cow;
|
||||
#define EO_OPTIONAL_COW_WRITE(_obj) ({ Efl_Object_Optional *_cow = eina_cow_write(efl_object_optional_cow, (const Eina_Cow_Data**)&(_obj->opt)); _cow; })
|
||||
#define EO_OPTIONAL_COW_END(_cow, _obj) eina_cow_done(efl_object_optional_cow, (const Eina_Cow_Data**)&(_obj->opt), _cow, EINA_TRUE)
|
||||
|
@ -146,6 +137,7 @@ extern Eina_Cow *efl_object_optional_cow;
|
|||
EO_OPTIONAL_COW_END(_obj##_cow, _obj); \
|
||||
}} while (0)
|
||||
#define EO_VTABLE(_obj) ((_obj)->opt->vtable ?: &((_obj)->klass->vtable))
|
||||
#define EO_VTABLE2(_obj) ((_obj)->opt->vtable ?: &((_obj)->klass->vtable))
|
||||
|
||||
typedef void (*Eo_Op_Func_Type)(Eo *, void *class_data);
|
||||
|
||||
|
@ -155,15 +147,9 @@ typedef struct
|
|||
const _Efl_Class *src;
|
||||
} op_type_funcs;
|
||||
|
||||
typedef struct _Dich_Chain2
|
||||
{
|
||||
op_type_funcs funcs[DICH_CHAIN_LAST_SIZE];
|
||||
unsigned short refcount;
|
||||
} Dich_Chain2;
|
||||
|
||||
struct _Dich_Chain1
|
||||
{
|
||||
Dich_Chain2 *chain2;
|
||||
struct _Eo_Vtable_Node{
|
||||
op_type_funcs *funcs;
|
||||
unsigned short count;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -203,7 +189,7 @@ struct _Efl_Class
|
|||
} iterators;
|
||||
|
||||
unsigned int obj_size; /**< size of an object of this class */
|
||||
unsigned int base_id;
|
||||
unsigned int class_id; /**< the id which can be used to find the slot in _eo_classes and vtables chains */
|
||||
unsigned int data_offset; /* < Offset of the data within object data. */
|
||||
unsigned int ops_count; /* < Offset of the data within object data. */
|
||||
|
||||
|
|
|
@ -329,7 +329,6 @@ EFL_END_TEST
|
|||
|
||||
EFL_START_TEST(efl_data_safe_fetch)
|
||||
{
|
||||
|
||||
Eo *obj = efl_add_ref(SIMPLE2_CLASS, NULL);
|
||||
fail_if(!obj || !efl_data_scope_safe_get(obj, SIMPLE2_CLASS));
|
||||
efl_unref(obj);
|
||||
|
|
Loading…
Reference in New Issue