Compare commits

...

16 Commits

Author SHA1 Message Date
Marcel Hollerbach b1edfa6149 wip 2020-03-18 14:38:43 +01:00
Marcel Hollerbach acdacefeb3 wip 2020-03-18 12:38:00 +01:00
Marcel Hollerbach 49da10a2b8 wip removal of more old code 2020-03-18 12:10:28 +01:00
Marcel Hollerbach c63e8a1806 wip 2020-03-18 11:11:47 +01:00
Marcel Hollerbach da0f0ca22f remove all the old vtable logic 2020-03-17 18:57:17 +01:00
Marcel Hollerbach 21dd906571 wip 2020-03-17 18:43:40 +01:00
Marcel Hollerbach 9d3698d383 wip eo 2020-03-17 18:42:28 +01:00
Marcel Hollerbach 69ff00c467 wip 2020-03-17 12:11:21 +01:00
Marcel Hollerbach aa0d9c5153 wip 2020-03-17 12:11:21 +01:00
Marcel Hollerbach d31813c18c wip 2020-03-17 12:11:21 +01:00
Marcel Hollerbach 7b74a5deb5 wip 2020-03-17 12:11:21 +01:00
Marcel Hollerbach da5e3c2f7e wip 2020-03-17 12:11:20 +01:00
Marcel Hollerbach 847bfc8852 wip 2020-03-17 12:11:20 +01:00
Marcel Hollerbach 01169be645 wip 2020-03-17 12:11:20 +01:00
Marcel Hollerbach abc4016e6e wip 2020-03-17 12:11:20 +01:00
Marcel Hollerbach 6527ad5c33 wip 2020-03-17 12:11:20 +01:00
3 changed files with 284 additions and 281 deletions

View File

@ -90,8 +90,7 @@ 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_Hash *_ops_storage2 = NULL;
static Eina_Spinlock _ops_storage_lock;
static const Efl_Object_Optional efl_object_optional_cow_default = {};
@ -104,9 +103,8 @@ 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);
static inline Efl_Object_Op _efl_object_api_op_id_get_internal2(const void *api_func);
/* Start of Dich */
@ -120,134 +118,152 @@ 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];
}
static inline void
_vtable_chain_alloc(Dich_Chain1 *chain1)
/**
* This inits the vtable wit hthe current size of allocated tables
*/
static void
_vtable_init(Eo_Vtable *vtable)
{
chain1->chain2 = calloc(1, sizeof(*(chain1->chain2)));
chain1->chain2->refcount = 1;
//we assume here that _eo_classes_last_id was called before
vtable->size = _eo_classes_last_id;
vtable->chain = calloc(vtable->size, sizeof(Eo_Vtable_Node));
}
static inline void _vtable_chain_write_prepare(Dich_Chain1 *dst);
static inline void
_vtable_chain_merge(Dich_Chain1 *dst, const Dich_Chain1 *src)
static void
_vtable_copy_all(Eo_Vtable *dest, const Eo_Vtable *src)
{
size_t j;
const op_type_funcs *sf = src->chain2->funcs;
op_type_funcs *df = dst->chain2->funcs;
if (df == sf)
for (int i = 0; i < src->size; ++i)
{
/* 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)))
if (src->chain[i].funcs)
{
_vtable_chain_write_prepare(dst);
df = dst->chain2->funcs + j;
memcpy(df, sf, sizeof(*df));
dest->chain[i] = src->chain[i];
}
}
}
static inline void
_vtable_chain_write_prepare(Dich_Chain1 *dst)
/**
* 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)
{
if (!dst->chain2)
{
_vtable_chain_alloc(dst);
return;
}
else if (dst->chain2->refcount == 1)
{
/* We own it, no need to duplicate */
return;
}
Dich_Chain1 old;
old.chain2 = dst->chain2;
_vtable_chain_alloc(dst);
_vtable_chain_merge(dst, &old);
_vtable_chain2_unref(old.chain2);
vtable->chain[class_id].funcs = (void*)0x1010101;
}
static inline void
_vtable_chain_copy_ref(Dich_Chain1 *dst, const Dich_Chain1 *src)
/**
* Copy 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)
{
if (dst->chain2)
dest->count = src->count;
dest->funcs = calloc(sizeof(op_type_funcs), src->count);
memcpy(dest->funcs, src->funcs, sizeof(op_type_funcs) * src->count);
}
/**
* Take over all the nodes of src, which are set.
* 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_merge_in(Eo_Vtable *dest, const Eo_Vtable *src)
{
for (unsigned int i = 0; i < src->size; ++i)
{
_vtable_chain_merge(dst, src);
}
else
{
dst->chain2 = src->chain2;
dst->chain2->refcount++;
//we assume that we *never* have allocated a chain when we call that here.
if (src->chain[i].funcs)
dest->chain[i] = src->chain[i];
}
}
static inline void
_vtable_copy_all(Eo_Vtable *dst, const Eo_Vtable *src)
/**
* 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)
{
Efl_Object_Op i;
const Dich_Chain1 *sc1 = src->chain;
Dich_Chain1 *dc1 = dst->chain;
for (i = 0 ; i < src->size ; i++, sc1++, dc1++)
dest->chain[class_id].count = length;
dest->chain[class_id].funcs = calloc(sizeof(op_type_funcs), dest->chain[class_id].count);
}
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 (sc1->chain2)
//if there is a source node evalulate if we need to copy it
if (src->chain[i].funcs)
{
_vtable_chain_copy_ref(dc1, sc1);
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];
}
}
}
}
}
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;
}
}
}
}
static inline const op_type_funcs *
_vtable_func_get(const Eo_Vtable *vtable, Efl_Object_Op op)
_vtable_func_get(const Eo_Vtable *vtable2, 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(vtable2->size <= class_id))
return NULL;
if (EINA_UNLIKELY(vtable2->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 &vtable2->chain[class_id].funcs[func_id];
}
static inline Eina_Bool
@ -255,59 +271,50 @@ _vtable_func_set(Eo_Vtable *vtable, const _Efl_Class *klass,
const _Efl_Class *hierarchy_klass, Efl_Object_Op op,
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;
op_type_funcs *func_storage;
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->vtable2.size > class_id)
hirachy_node = &klass->parent->vtable2.chain[class_id];
if (hierarchy_klass)
hirachy_node = &hierarchy_klass->vtable2.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);
func_storage = &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
{
if (!allow_same_override && (fsrc->src == klass))
if (!allow_same_override && (func_storage->src == klass))
{
const _Efl_Class *op_kls = _eo_op_class_get(op);
ERR("Class '%s': Overriding already set func %p for op %d (%s) with %p.",
klass->desc->name, fsrc->func, op, op_kls->desc->name, func);
klass->desc->name, func_storage->func, op, op_kls->desc->name, func);
return EINA_FALSE;
}
}
fsrc->func = func;
fsrc->src = klass;
func_storage->src = klass;
func_storage->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))
@ -371,7 +378,7 @@ _eo_kls_itr_next(const _Efl_Class *orig_kls, const _Efl_Class *cur_klass,
if (super) kls_itr++;
while (*kls_itr)
{
const op_type_funcs *fsrc = _vtable_func_get(&(*kls_itr)->vtable, op);
const op_type_funcs *fsrc = _vtable_func_get(&(*kls_itr)->vtable2, op);
if (!fsrc || !fsrc->func)
{
kls_itr++;
@ -478,7 +485,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 +551,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->vtable2, op);
if (func == NULL) goto composite_continue;
if (EINA_LIKELY(func->func && func->src))
@ -604,7 +611,7 @@ ok_klass:
{
EO_CLASS_POINTER_GOTO_PROXY(eo_id, _klass, err_klass);
klass = _klass;
vtable = &klass->vtable;
vtable = &klass->vtable2;
cur_klass = _super_klass;
if (cur_klass) _super_klass = NULL;
call->obj = NULL;
@ -623,7 +630,7 @@ obj_super:
{
/* Doing a efl_super(obj, EFL_OBJECT_OVERRIDE_CLASS) should
* result in calling as if it's a normal class. */
vtable = &klass->vtable;
vtable = &klass->vtable2;
cur_klass = NULL;
}
@ -637,7 +644,7 @@ err_klass:
on_null:
if (EINA_UNLIKELY(efl_del_api_generation != _efl_object_init_generation))
{
_efl_del_api_op_id = _efl_object_api_op_id_get_internal(EFL_FUNC_COMMON_OP_FUNC(efl_del));
_efl_del_api_op_id = _efl_object_api_op_id_get_internal2(EFL_FUNC_COMMON_OP_FUNC(efl_del));
efl_del_api_generation = _efl_object_init_generation;
}
if (op != _efl_del_api_op_id)
@ -674,13 +681,13 @@ _eo_api_func_equal(const void *api_func1, const void *api_func2)
}
static inline Efl_Object_Op
_efl_object_api_op_id_get_internal(const void *api_func)
_efl_object_api_op_id_get_internal2(const void *api_func)
{
eina_spinlock_take(&_ops_storage_lock);
#ifndef _WIN32
Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage, &api_func);
Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage2, &api_func);
#else
Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage, api_func);
Efl_Object_Op op = (uintptr_t) eina_hash_find(_ops_storage2, api_func);
#endif
eina_spinlock_release(&_ops_storage_lock);
@ -691,7 +698,7 @@ _efl_object_api_op_id_get_internal(const void *api_func)
EAPI Efl_Object_Op
_efl_object_api_op_id_get(const void *api_func)
{
Efl_Object_Op op = _efl_object_api_op_id_get_internal(api_func);
Efl_Object_Op op = _efl_object_api_op_id_get_internal2(api_func);
if (op == EFL_NOOP)
{
@ -709,7 +716,7 @@ _efl_object_op_api_id_get(const void *api_func, const Eo *eo_obj, const char *ap
#ifndef EO_DEBUG
if (!eo_obj) return EFL_NOOP;
#endif
op = _efl_object_api_op_id_get_internal(api_func);
op = _efl_object_api_op_id_get_internal2(api_func);
if (op == EFL_NOOP)
{
EO_OBJ_POINTER(eo_obj, obj);
@ -727,23 +734,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 *vtable2, 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(vtable2, class_id);
if (!op_descs || !ops->count)
return EINA_TRUE;
#ifdef EO_DEBUG
check_equal = EINA_TRUE;
@ -776,43 +785,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_internal2(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(vtable2, 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_internal2(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_storage2, &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_storage2, 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 = vtable2->chain[op2_class_id];
_vtable_copy_node(&vtable2->chain[op2_class_id], &node);
hitmap[op2_class_id] = EINA_TRUE;
}
if (!_vtable_func_set(vtable2, klass, override_class, op2, op_desc->func, EINA_TRUE))
return EINA_FALSE;
}
return EINA_TRUE;
}
@ -821,6 +848,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,10 +860,11 @@ 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->base_id2 = _UNMASK_ID(klass->header.id) - 1;
hitmap = alloca(sizeof(Eina_Bool) * klass->base_id2);
memset(hitmap, 0, sizeof(Eina_Bool) * klass->base_id2);
_vtable_init(&klass->vtable, DICH_CHAIN1(_eo_ops_last_id) + 1);
_vtable_init(&klass->vtable2);
/* Flatten the function array */
{
@ -844,11 +873,44 @@ efl_class_functions_set(const Efl_Class *klass_id, const Efl_Object_Ops *object_
/* Skip ourselves. */
for ( mro_itr-- ; mro_itr > klass->mro ; mro_itr--)
_vtable_copy_all(&klass->vtable, &(*mro_itr)->vtable);
{
_vtable_merge_defined_api(&klass->vtable2, &(*mro_itr)->vtable2, hitmap);
}
/*add slots for the interfaces 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->vtable2, &ext->vtable2, 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_internal2(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->vtable2.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->vtable2, required_klass->vtable2.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_merge_in(&klass->vtable2, &required_klass->vtable2);
}
}
}
}
return _eo_class_funcs_set(&klass->vtable2, object_ops, klass, klass, EINA_FALSE, klass->base_id2, hitmap);
err_funcs:
ERR("Class %s already had its functions set..", klass->desc->name);
return EINA_FALSE;
@ -1098,9 +1160,9 @@ _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);
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
//eina_freeq_ptr_main_add(obj->opt->vtable, free, 0);
//FIXME free vtable
EO_OPTIONAL_COW_SET(obj, vtable2, NULL);
}
_eo_id_release((Eo_Id) _eo_obj_id_get(obj));
@ -1190,22 +1252,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)
{
@ -1361,7 +1407,7 @@ 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);
//FIXME free all vtable2 classes
}
EINA_TRASH_CLEAN(&klass->objects.trash, data)
@ -1376,32 +1422,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 +1730,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);
@ -1731,34 +1745,43 @@ efl_object_override(Eo *eo_id, const Efl_Object_Ops *ops)
if (ops)
{
Eo_Vtable *vtable = obj->opt->vtable;
Eo_Vtable *vtable2 = obj->opt->vtable2;
//copy all the vtable nodes that we are going to change later on
Eina_Bool *hitmap;
if (!vtable)
if (!vtable2)
{
vtable = calloc(1, sizeof(*vtable));
_vtable_init(vtable, obj->klass->vtable.size);
_vtable_copy_all(vtable, &obj->klass->vtable);
vtable2 = calloc(1, sizeof(*vtable2));
_vtable_init(vtable2);
_vtable_copy_all(vtable2, &obj->klass->vtable2);
}
if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, 0, EINA_TRUE))
hitmap = alloca(vtable2->size);
memset(hitmap, 0, vtable2->size);
if (!_eo_class_funcs_set(vtable2, ops, obj->klass, klass, EINA_TRUE, obj->klass->base_id2, 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);
if (obj->opt->vtable2 == vtable2)
{
EO_OPTIONAL_COW_SET(obj, vtable2, NULL);
}
else
_vtable_free(vtable);
{
//FIXME free this
}
goto err;
}
EO_OPTIONAL_COW_SET(obj, vtable, vtable);
EO_OPTIONAL_COW_SET(obj, vtable2, vtable2);
}
else
{
if (obj->opt->vtable)
if (obj->opt->vtable2)
{
_vtable_free(obj->opt->vtable);
EO_OPTIONAL_COW_SET(obj, vtable, NULL);
//FIXME free this
EO_OPTIONAL_COW_SET(obj, vtable2, NULL);
}
}
@ -1791,10 +1814,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->vtable2.size <= klass->base_id2))
return EINA_FALSE;
return (func && (func->func == _eo_class_isa_func));;
return !!lookinto->vtable2.chain[klass->base_id2].funcs;
}
domain = ((Eo_Id)eo_id >> SHIFT_DOMAIN) & MASK_DOMAIN;
@ -1813,15 +1836,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->vtable2;
if (EINA_UNLIKELY(vtable.size <= klass->base_id2))
return EINA_FALSE;
isa = !!vtable.chain[klass->base_id2].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 +1866,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->vtable2.size <= klass->base_id2))
return EINA_FALSE;
isa = !!obj->klass->vtable2.chain[klass->base_id2].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 +2351,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)
{
@ -2354,9 +2378,9 @@ efl_object_init(void)
eina_magic_string_static_set(EO_CLASS_EINA_MAGIC,
EO_CLASS_EINA_MAGIC_STR);
#ifndef _WIN32
_ops_storage = eina_hash_pointer_new(NULL);
_ops_storage2 = eina_hash_pointer_new(NULL);
#else
_ops_storage = eina_hash_string_superfast_new(NULL);
_ops_storage2 = eina_hash_string_superfast_new(NULL);
#endif
_eo_table_data_shared = _eo_table_data_new(EFL_ID_DOMAIN_SHARED);
@ -2384,12 +2408,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);
@ -2449,8 +2467,8 @@ efl_object_shutdown(void)
_eo_classes_release();
eina_lock_release(&_efl_class_creation_lock);
eina_hash_free(_ops_storage);
_ops_storage = NULL;
eina_hash_free(_ops_storage2);
_ops_storage2 = NULL;
eina_spinlock_free(&_ops_storage_lock);
eina_lock_free(&_efl_class_creation_lock);

View File

@ -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 *vtable2;
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->vtable2 ?: &((_obj)->klass->vtable2))
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
@ -178,7 +164,7 @@ struct _Efl_Class
const _Efl_Class *parent;
const Efl_Class_Description *desc;
Eo_Vtable vtable;
Eo_Vtable vtable2;
const _Efl_Class **extensions;
@ -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 base_id2;
unsigned int data_offset; /* < Offset of the data within object data. */
unsigned int ops_count; /* < Offset of the data within object data. */
@ -325,7 +311,7 @@ _efl_del_internal(_Eo_Object *obj, const char *func_name, const char *file, int
static inline Eina_Bool
_obj_is_override(_Eo_Object *obj)
{
return obj->opt->vtable != NULL;
return obj->opt->vtable2 != NULL;
}
void _eo_free(_Eo_Object *obj, Eina_Bool manual_free);

View File

@ -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);