eo2: call stack Proof Of Concept
authorJérémy Zurcher <jeremy@asynk.ch>
Wed, 25 Dec 2013 14:16:34 +0000 (15:16 +0100)
committerTom Hacohen <tom@stosb.com>
Thu, 10 Apr 2014 03:20:16 +0000 (04:20 +0100)
no grow/shrink or thread local storage

src/lib/eo/Eo.h
src/lib/eo/eo.c
src/lib/eo/eo2_base_class.h
src/lib/eo/eo_private.h

index e5fa687..457e3ca 100644 (file)
@@ -614,48 +614,40 @@ EAPI Eina_Bool eo_shutdown(void);
 EAPI void
 eo2_class_funcs_set(Eo_Class *klass_id);
 
-// opaque type used to pass object pointer to EAPI calls
-typedef struct _Eo_Internal _Eo;
-
 // to fetch internal function and object data at once
 typedef struct _Eo2_Op_Call_Data
 {
-   void *func;
-   void *data;
+   Eo    *obj_id;
+   void  *func;
+   void  *data;
 } Eo2_Op_Call_Data;
 
-// EAPI function declaration first argument
-#define eo2_a _Eo *obj, Eo *objid
-// EAPI function call first argument
-#define eo2_o _obj_, _objid_
-
 // to pass the internal function call to EO2_FUNC_BODY (as Func parameter)
-#define EO2_FUNC_CALL(...) _func_(objid, call.data, __VA_ARGS__)
+#define EO2_FUNC_CALL(...) _func_(call.obj_id, call.data, __VA_ARGS__)
 
 // cache OP id, get real fct and object data then do the call
 #define _EO2_FUNC_COMMON(Name, Ret, Func, DefRet)                       \
      static Eo_Op op = EO_NOOP;                                         \
-     if ( op == EO_NOOP ) op = eo2_get_op_id(obj, (void*)Name);         \
+     if ( op == EO_NOOP ) op = eo2_get_op_id((void*)Name);              \
      Eo2_Op_Call_Data call;                                             \
-     if (!eo2_call_resolve(obj, op, &call)) return DefRet;              \
+     if (!eo2_call_resolve(op, &call)) return DefRet;                   \
      __##Name##_func _func_ = (__##Name##_func) call.func;              \
      return Func;                                                       \
 
-/* XXX: Essential, because we need to adjust objid for comp objects. */
 // to define an EAPI function
 #define EO2_FUNC_BODY(Name, Ret, DefRet)                                \
   Ret                                                                   \
-  Name(_Eo *obj, Eo *objid)                                             \
+  Name()                                                                \
   {                                                                     \
      typedef Ret (*__##Name##_func)(Eo *, void *obj_data);              \
-     _EO2_FUNC_COMMON(Name, Ret, _func_(objid, call.data), DefRet)      \
+     _EO2_FUNC_COMMON(Name, Ret, _func_(call.obj_id, call.data), DefRet)\
   }
 
 #define EO2_VOID_FUNC_BODY(Name) EO2_FUNC_BODY(Name, void, )
 
 #define EO2_FUNC_BODYV(Name, Ret, Func, DefRet, ...)                    \
   Ret                                                                   \
-  Name(_Eo *obj, Eo *objid, __VA_ARGS__)                                \
+  Name(__VA_ARGS__)                                                     \
   {                                                                     \
      typedef Ret (*__##Name##_func)(Eo *, void *obj_data, __VA_ARGS__); \
      _EO2_FUNC_COMMON(Name, Ret, Func, DefRet)                          \
@@ -670,21 +662,17 @@ typedef struct _Eo2_Op_Call_Data
 #define EO2_OP_SENTINEL { NULL, NULL, 0, EO_OP_TYPE_INVALID, NULL}
 
 // returns the OP id corresponding to the given api_func
-EAPI Eo_Op eo2_get_op_id(_Eo *obj, void *api_func);
+EAPI Eo_Op eo2_get_op_id(void *api_func);
 
 // gets the real function pointer and the object data
-#define eo2_call_resolve(obj_id, op, call) eo2_call_resolve_internal(obj_id, NULL, op, call)
-EAPI Eina_Bool eo2_call_resolve_internal(_Eo *obj, const Eo_Class *klass, Eo_Op op, Eo2_Op_Call_Data *call);
-
-// start of eo2_do barrier, gets the object pointer and ref it
-EAPI _Eo * eo2_do_start(Eo *obj_id);
+#define eo2_call_resolve(op, call) eo2_call_resolve_internal(NULL, op, call)
+EAPI Eina_Bool eo2_call_resolve_internal(const Eo_Class *klass, Eo_Op op, Eo2_Op_Call_Data *call);
 
-// end of the eo2_do barrier, unref the obj
-EAPI void eo2_do_end(_Eo *obj);
+// start of eo2_do barrier, gets the object pointer and ref it, put it on the stask
+EAPI Eina_Bool eo2_do_start(Eo *obj_id);
 
-// optional helper
-#define eo2_call(api_func) api_func(eo2_o)
-#define eo2_callv(api_func, ...) api_func(eo2_o, __VA_ARGS__)
+// end of the eo2_do barrier, unref the obj, move the stack pointer
+EAPI void eo2_do_end();
 
 // eo object method calls batch,
 // DO NOT use return statement in it, use break if necessary
@@ -692,11 +680,9 @@ EAPI void eo2_do_end(_Eo *obj);
   do                                            \
     {                                           \
        Eo *_objid_ = objid;                     \
-       _Eo *_obj_ = eo2_do_start(_objid_);      \
-       if (!_obj_) break;                       \
+       if (!eo2_do_start(_objid_)) break;       \
        do { __VA_ARGS__ ; } while (0);          \
-       eo2_do_end(_obj_);                       \
-       _obj_ = NULL;                            \
+       eo2_do_end();                            \
     } while (0)
 
 // FIXME
index 906183a..d21b5f3 100644 (file)
@@ -257,25 +257,77 @@ _eo_kls_itr_func_get(const _Eo_Class *cur_klass, Eo_Op op)
 
 /************************************ EO2 ************************************/
 
-EAPI _Eo *
+// FIXME: per thread stack, grow/shrink
+#define EO2_INVALID_DATA (void *) -1
+#define EO2_CALL_STACK_SIZE 5
+typedef struct _Eo2_Stack_Frame
+{
+   Eo               *obj_id;
+   _Eo              *obj;
+   void             *obj_data;
+
+} Eo2_Stack_Frame;
+
+typedef struct _Eo2_Call_Stack {
+     Eo2_Stack_Frame stack[EO2_CALL_STACK_SIZE];
+     Eo2_Stack_Frame *frame_ptr;
+} Eo2_Call_Stack;
+
+static Eo2_Call_Stack eo2_call_stack = {
+       {
+            { NULL, NULL, EO2_INVALID_DATA },
+            { NULL, NULL, EO2_INVALID_DATA },
+            { NULL, NULL, EO2_INVALID_DATA },
+            { NULL, NULL, EO2_INVALID_DATA },
+            { NULL, NULL, EO2_INVALID_DATA },
+       },
+       NULL };
+
+EAPI Eina_Bool
 eo2_do_start(Eo *obj_id)
 {
-   EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, NULL);
+   EO_OBJ_POINTER_RETURN_VAL(obj_id, obj, EINA_FALSE);
    _eo_ref(obj);
-   return obj;
+
+   if (eo2_call_stack.frame_ptr == NULL)
+     eo2_call_stack.frame_ptr = &eo2_call_stack.stack[0];
+   else
+     eo2_call_stack.frame_ptr++;
+
+   if (eo2_call_stack.frame_ptr->obj_id != NULL)
+     ERR("eo2 call stack is not clear, you must have used a return statement in a eo2_do macro");
+
+   if ((eo2_call_stack.frame_ptr - eo2_call_stack.stack) >= EO2_CALL_STACK_SIZE)
+     ERR("eo2 call stack overflow !!!");
+
+   eo2_call_stack.frame_ptr->obj = obj;
+   eo2_call_stack.frame_ptr->obj_id = obj_id;
+   eo2_call_stack.frame_ptr->obj_data = EO2_INVALID_DATA;
+
+   return EINA_TRUE;
 }
 
 EAPI void
-eo2_do_end(_Eo *obj)
+eo2_do_end()
 {
-   _eo_unref(obj);
+   _eo_unref(eo2_call_stack.frame_ptr->obj);
+
+   eo2_call_stack.frame_ptr->obj = NULL;
+   eo2_call_stack.frame_ptr->obj_id = NULL;
+   eo2_call_stack.frame_ptr->obj_data = EO2_INVALID_DATA;
+
+   if (eo2_call_stack.frame_ptr == &eo2_call_stack.stack[0])
+     eo2_call_stack.frame_ptr = NULL;
+   else
+     eo2_call_stack.frame_ptr--;
 }
 
 EAPI Eina_Bool
-eo2_call_resolve_internal(_Eo *obj, const Eo_Class *klass_id, Eo_Op op, Eo2_Op_Call_Data *call)
+eo2_call_resolve_internal(const Eo_Class *klass_id, Eo_Op op, Eo2_Op_Call_Data *call)
 {
    const _Eo_Class *klass;
    const op_type_funcs *func;
+   const _Eo * obj = eo2_call_stack.frame_ptr->obj;
 
    if (klass_id)
       klass = _eo_class_pointer_get(klass_id);
@@ -285,8 +337,19 @@ eo2_call_resolve_internal(_Eo *obj, const Eo_Class *klass_id, Eo_Op op, Eo2_Op_C
    func = _eo_kls_itr_func_get(klass, op);
    if (EINA_LIKELY(func != NULL))
      {
+        call->obj_id = eo2_call_stack.frame_ptr->obj_id;
         call->func = func->func;
-        call->data = _eo_data_scope_get(obj, func->src);
+
+        if (func->src == obj->klass)
+          {
+             if (eo2_call_stack.frame_ptr->obj_data == EO2_INVALID_DATA)
+               eo2_call_stack.frame_ptr->obj_data = _eo_data_scope_get(obj, func->src);
+
+             call->data = eo2_call_stack.frame_ptr->obj_data;
+          }
+        else
+          call->data = _eo_data_scope_get(obj, func->src);
+
         return EINA_TRUE;
      }
 
@@ -297,11 +360,12 @@ eo2_call_resolve_internal(_Eo *obj, const Eo_Class *klass_id, Eo_Op op, Eo2_Op_C
 
 
 EAPI Eo_Op
-eo2_get_op_id(_Eo *obj, void *api_func)
+eo2_get_op_id(void *api_func)
 {
    int imin, imax, imid;
    Eo2_Op_Description *op_desc;
    Eo2_Op_Description *op_descs;
+   const _Eo * obj = eo2_call_stack.frame_ptr->obj;
 
    imin = 0;
    imax = obj->klass->desc->ops.count - 1;
index c4400b8..ff40eb5 100644 (file)
 /* #include "eo_private.h" */
 
 EAPI void
-data_set(eo2_a, const char *key, const void *data, eo_base_data_free_func free_func);
+data_set(const char *key, const void *data, eo_base_data_free_func free_func);
 
 EAPI void
-data_get(eo2_a, const char *key);
+data_get(const char *key);
 
 EAPI void
-data_del(eo2_a, const char *key);
+data_del(const char *key);
 
 EAPI void
-wref_add(eo2_a, Eo **wref);
+wref_add(Eo **wref);
 
 EAPI void
-wref_del(eo2_a, Eo **wref);
+wref_del(Eo **wref);
 
 EAPI void
-ev_cb_priority_add(eo2_a, const Eo_Event_Description *desc,
+ev_cb_priority_add(const Eo_Event_Description *desc,
                    Eo_Callback_Priority priority, Eo_Event_Cb func,
                    const void *user_data);
 
 EAPI void
-ev_cb_del(eo2_a, const Eo_Event_Description *desc, Eo_Event_Cb func,
+ev_cb_del(const Eo_Event_Description *desc, Eo_Event_Cb func,
           const void *user_data);
 
 EAPI void
-ev_cb_array_priority_add(eo2_a, const Eo_Callback_Array_Item *array,
+ev_cb_array_priority_add(const Eo_Callback_Array_Item *array,
                          Eo_Callback_Priority priority, const void *user_data);
 
 EAPI void
-ev_cb_array_del(eo2_a, const Eo_Callback_Array_Item *array,
+ev_cb_array_del(const Eo_Callback_Array_Item *array,
                 const void *user_data);
 
 EAPI Eina_Bool
-ev_cb_call(eo2_a, const Eo_Event_Description *desc, void *event_info);
+ev_cb_call(const Eo_Event_Description *desc, void *event_info);
 
 EAPI void
-ev_cb_forwarder_add(eo2_a, const Eo_Event_Description *desc, Eo *new_obj);
+ev_cb_forwarder_add(const Eo_Event_Description *desc, Eo *new_obj);
 
 EAPI void
-ev_cb_forwarder_del(eo2_a, const Eo_Event_Description *desc, Eo *new_obj);
+ev_cb_forwarder_del(const Eo_Event_Description *desc, Eo *new_obj);
 
 EAPI void
-ev_freeze(eo2_a);
+ev_freeze();
 
 EAPI void
-ev_thaw(eo2_a);
+ev_thaw();
 
 EAPI int
-ev_freeze_get(eo2_a);
+ev_freeze_get();
 
 EAPI void
-ev_global_freeze(eo2_a);
+ev_global_freeze();
 
 EAPI void
-ev_global_thaw(eo2_a);
+ev_global_thaw();
 
 EAPI int
-ev_global_freeze_get(eo2_a);
+ev_global_freeze_get();
 
 EAPI void
-dbg_info_get(eo2_a);
+dbg_info_get();
 
 EAPI void
 eo2_dbg_info_free(Eo_Dbg_Info *info);
index a985556..621bab4 100644 (file)
@@ -60,6 +60,7 @@ typedef uintptr_t Eo_Id;
 typedef struct _Eo_Class _Eo_Class;
 typedef struct _Eo_Object _Eo_Object;
 typedef struct _Eo_Base Eo_Base;
+typedef struct _Eo_Internal _Eo;
 
 /* Retrieves the pointer to the object from the id */
 static inline _Eo_Object *_eo_obj_pointer_get(const Eo_Id obj_id);