static Eina_Hash *_ops_storage = NULL;
static Eina_Spinlock _ops_storage_lock;
+static const Efl_Object_Optional efl_object_optional_cow_default = {};
+Eina_Cow *efl_object_optional_cow = NULL;
+
static size_t _eo_sz = 0;
static size_t _eo_class_sz = 0;
obj = _obj;
klass = _obj->klass;
- vtable = obj->vtable;
+ vtable = EO_VTABLE(obj);
if (_obj_is_override(obj) && cur_klass &&
(_eo_class_id_get(cur_klass) == EFL_OBJECT_OVERRIDE_CLASS))
{
Eina_List *itr;
Eo *emb_obj_id;
- EINA_LIST_FOREACH(obj->composite_objects, itr, emb_obj_id)
+ EINA_LIST_FOREACH(obj->opt->composite_objects, itr, emb_obj_id)
{
EO_OBJ_POINTER_PROXY(emb_obj_id, emb_obj);
if (EINA_UNLIKELY(!emb_obj)) continue;
- func = _vtable_func_get(emb_obj->vtable, cache->op);
+ func = _vtable_func_get(EO_VTABLE(emb_obj), cache->op);
if (func == NULL) goto composite_continue;
if (EINA_LIKELY(func->func && func->src))
}
eina_spinlock_release(&klass->objects.trash_lock);
+ obj->opt = eina_cow_alloc(efl_object_optional_cow);
obj->refcount++;
obj->klass = klass;
- obj->vtable = &klass->vtable;
#ifndef HAVE_EO_ID
EINA_MAGIC_SET((Eo_Header *) obj, EO_EINA_MAGIC);
_efl_object_parent_sink_set(obj, EINA_FALSE);
}
-
void
_eo_free(_Eo_Object *obj, Eina_Bool manual_free EINA_UNUSED)
{
#endif
if (_obj_is_override(obj))
{
- _vtable_func_clean_all(obj->vtable);
- eina_freeq_ptr_main_add(obj->vtable, free, 0);
- obj->vtable = &klass->vtable;
+ _vtable_func_clean_all(obj->opt->vtable);
+ eina_freeq_ptr_main_add(obj->opt->vtable, free, 0);
+ EO_OPTIONAL_COW_SET(obj, vtable, NULL);
}
_eo_id_release((Eo_Id) _eo_obj_id_get(obj));
+ eina_cow_free(efl_object_optional_cow, (Eina_Cow_Data *) &obj->opt);
eina_spinlock_take(&klass->objects.trash_lock);
if ((klass->objects.trash_count <= 8) && (EINA_LIKELY(!_eo_trash_bypass)))
efl_object_override(Eo *eo_id, const Efl_Object_Ops *ops)
{
EO_OBJ_POINTER_RETURN_VAL(eo_id, obj, EINA_FALSE);
- EO_CLASS_POINTER_GOTO(EFL_OBJECT_OVERRIDE_CLASS, klass, err_done);
- Eo_Vtable *previous = obj->vtable;
+ EO_CLASS_POINTER_GOTO(EFL_OBJECT_OVERRIDE_CLASS, klass, err);
if (ops)
{
- if (obj->vtable == &obj->klass->vtable)
+ Eo_Vtable *vtable;
+
+ if (EINA_UNLIKELY(obj->opt->vtable != NULL))
{
- obj->vtable = calloc(1, sizeof(*obj->vtable));
- _vtable_init(obj->vtable, previous->size);
- _vtable_copy_all(obj->vtable, previous);
- // rare so move error handling to end to save l1 instruction cache
- if (!_eo_class_funcs_set(obj->vtable, ops, obj->klass,
- klass, 0, EINA_TRUE))
- goto err;
- goto done;
+ ERR("Function table already overridden, not allowed to override again. "
+ "Call with NULL to reset the function table first.");
+ goto err;
}
- // rare so move error handling to end to save l1 instruction cache
- else goto err_already;
+
+ vtable = calloc(1, sizeof(*vtable));
+ _vtable_init(vtable, obj->klass->vtable.size);
+ _vtable_copy_all(vtable, &obj->klass->vtable);
+ if (!_eo_class_funcs_set(vtable, ops, obj->klass, klass, 0, EINA_TRUE))
+ {
+ // FIXME: Maybe leaking some chain stuff from copy above?
+ ERR("Failed to override functions for %p", eo_id);
+ free(vtable);
+ goto err;
+ }
+
+ EO_OPTIONAL_COW_SET(obj, vtable, vtable);
}
else
{
- if (obj->vtable != &obj->klass->vtable)
+ if (obj->opt->vtable)
{
- eina_freeq_ptr_main_add(obj->vtable, free, 0);
- obj->vtable = (Eo_Vtable *) &obj->klass->vtable;
+ eina_freeq_ptr_main_add(obj->opt->vtable, free, 0);
+ EO_OPTIONAL_COW_SET(obj, vtable, NULL);
}
}
-done:
+
EO_OBJ_DONE(eo_id);
return EINA_TRUE;
-err_already:
- ERR("Function table already overridden, not allowed to override again. "
- "Call with NULL to reset the function table first.");
- goto err_done;
err:
- ERR("Failed to override functions for %p", eo_id);
-err_done:
EO_OBJ_DONE(eo_id);
return EINA_FALSE;
}
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
- (obj->vtable, klass->base_id + klass->ops_count);
+ (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;
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
- (obj->vtable, klass->base_id + klass->ops_count);
+ (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;
efl_del_intercept_set(Eo *obj_id, Efl_Del_Intercept del_intercept_func)
{
EO_OBJ_POINTER_RETURN(obj_id, obj);
- obj->del_intercept = del_intercept_func;
+ EO_OPTIONAL_COW_SET(obj, del_intercept, del_intercept_func);
EO_OBJ_DONE(obj_id);
}
EAPI Efl_Del_Intercept
efl_del_intercept_get(const Eo *obj_id)
{
- EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
Efl_Del_Intercept func;
- func = obj->del_intercept;
+
+ EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
+ func = obj->opt->del_intercept;
EO_OBJ_DONE(obj_id);
return func;
}
_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);
+
_efl_add_fallback_init();
eina_log_timing(_eo_log_dom,
_eo_table_data_shared_data = NULL;
}
+ eina_cow_del(efl_object_optional_cow);
+ efl_object_optional_cow = NULL;
+
_eo_log_obj_shutdown();
eina_log_domain_unregister(_eo_log_dom);
EOLIAN static Eina_Bool
_efl_object_composite_attach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id)
{
+ Efl_Object_Optional *opt;
Eo *emb_obj_id = NULL;
EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
/* Don't composite if we already have a composite object of this type */
{
Eina_List *itr;
- EINA_LIST_FOREACH(parent->composite_objects, itr, emb_obj_id)
+ EINA_LIST_FOREACH(parent->opt->composite_objects, itr, emb_obj_id)
{
EO_OBJ_POINTER_GOTO(emb_obj_id, emb_obj, err_klass);
if (EINA_UNLIKELY(emb_obj->klass == comp_obj->klass)) goto err_klass;
_efl_object_extension_need(comp_pd);
comp_pd->ext->composite_parent = parent_id;
- parent->composite_objects = eina_list_prepend(parent->composite_objects, comp_obj_id);
+ opt = EO_OPTIONAL_COW_WRITE(parent);
+ opt->composite_objects = eina_list_prepend(opt->composite_objects, comp_obj_id);
+ EO_OPTIONAL_COW_END(opt, parent);
if (emb_obj_id) EO_OBJ_DONE(emb_obj_id);
EO_OBJ_DONE(parent_id);
EOLIAN static Eina_Bool
_efl_object_composite_detach(Eo *parent_id, Efl_Object_Data *pd EINA_UNUSED, Eo *comp_obj_id)
{
+ Efl_Object_Optional *opt;
+
EO_OBJ_POINTER_RETURN_VAL(comp_obj_id, comp_obj, EINA_FALSE);
EO_OBJ_POINTER_GOTO(parent_id, parent, err_parent);
// unlikely so improve l1 instr cache by using goto
if (!efl_composite_part_is(comp_obj_id)) goto err_part;
- parent->composite_objects = eina_list_remove(parent->composite_objects, comp_obj_id);
+ opt = EO_OPTIONAL_COW_WRITE(parent);
+ opt->composite_objects = eina_list_remove(opt->composite_objects, comp_obj_id);
+ EO_OPTIONAL_COW_END(opt, parent);
+
/* Clear the comp parent on the child. */
{
Efl_Object_Data *comp_pd = efl_data_scope_get(comp_obj_id, EFL_OBJECT_CLASS);
{
EO_OBJ_POINTER_RETURN(obj, obj_data);
obj_data2 = obj_data;
- if (obj_data->composite_objects) goto composite_obj;
+ if (obj_data->opt->composite_objects) goto composite_obj;
composite_obj_back:
EO_OBJ_DONE(obj);
}
{
Eina_List *itr, *next;
Eo *emb_obj_id;
- EINA_LIST_FOREACH_SAFE(obj_data2->composite_objects, itr, next, emb_obj_id)
+
+ EINA_LIST_FOREACH_SAFE(obj_data2->opt->composite_objects, itr, next, emb_obj_id)
{
efl_composite_detach(obj, emb_obj_id);
}
typedef uintptr_t Eo_Id;
typedef struct _Efl_Class _Efl_Class;
typedef struct _Eo_Header Eo_Header;
+typedef struct _Efl_Object_Optional Efl_Object_Optional;
/* Allocates an entry for the given object */
static inline Eo_Id _eo_id_allocate(const _Eo_Object *obj, const Eo *parent_id);
Eo_Id id;
};
+struct _Efl_Object_Optional
+{
+ Eo_Vtable *vtable;
+ Eina_List *composite_objects;
+ Efl_Del_Intercept del_intercept;
+};
+
struct _Eo_Object
{
Eo_Header header;
Eina_Inlist *data_xrefs;
#endif
- Eo_Vtable *vtable;
-
- Eina_List *composite_objects;
- Efl_Del_Intercept del_intercept;
+ const Efl_Object_Optional *opt; // eina cow
short refcount;
short user_refcount;
#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)
+#define EO_OPTIONAL_COW_SET(_obj, _field, _value) do { \
+ typeof (_value) _val = _value; \
+ if (_obj->opt->_field != _val) {\
+ Efl_Object_Optional *_obj##_cow = EO_OPTIONAL_COW_WRITE(_obj); \
+ _obj##_cow->_field = _val; \
+ EO_OPTIONAL_COW_END(_obj##_cow, _obj); \
+ }} while (0)
+#define EO_VTABLE(_obj) ((_obj)->opt->vtable ?: &((_obj)->klass->vtable))
+
typedef void (*Eo_Op_Func_Type)(Eo *, void *class_data);
typedef struct
{
Eina_List *itr, *itr_n;
Eo *emb_obj;
- EINA_LIST_FOREACH_SAFE(obj->composite_objects, itr, itr_n, emb_obj)
+ EINA_LIST_FOREACH_SAFE(obj->opt->composite_objects, itr, itr_n, emb_obj)
{
efl_composite_detach(_eo_obj_id_get(obj), emb_obj);
}
static inline Eina_Bool
_obj_is_override(_Eo_Object *obj)
{
- return (obj->vtable != &obj->klass->vtable);
+ return obj->opt->vtable != NULL;
}
void _eo_free(_Eo_Object *obj, Eina_Bool manual_free);
return;
}
- if (obj->del_intercept)
+ if (obj->opt->del_intercept)
{
Eo *obj_id = _eo_obj_id_get(obj);
efl_ref(obj_id);
- obj->del_intercept(obj_id);
+ obj->opt->del_intercept(obj_id);
return;
}