[aspectc-user] Proceed() Implementation details

Olaf Spinczyk Olaf.Spinczyk at informatik.uni-erlangen.de
Mon Sep 27 10:05:49 CEST 2004


Hello,

Swati Pradhan wrote:
> Hi all,
> 
> I am new to AOP and for my research work I have to
> look in the implementation details of AO languages. 
> 
> Currently, I am looking for the implementation of
> around advice proceed()) in AspectJ and AspectC++. 
> 
> For AspectC++, I looked for the papers and even in the
> source code, to get some documentation or explaination
> of how proceed() is implemented (and why that approach
> was used), but couldnt find it. 
> 
> Could somebody explain it to me or give me a reference
> where it is well explained...
> Also, how this implemetation is compared with
> AspectJ's proceed() implemetation...
> 
> Thanks in advance...
> Swati

you get the best impression by looking into the generated code. For 
example, weave the following code with ac++ (ac++ -c <input-file> -o 
<output-file> -p . --no_line -a 0):

---start (<input-file>)---
#include <cstdio>
using std::printf;

aspect Foo {
   advice execution ("% main(...)") : around () {
     printf ("-->\n");
     tjp->proceed ();
     printf ("<--\n");
   }
};

int main (int argc, char **argv) {
   printf ("main() running\n");
   return 0;
}
---end---

here is the result:

---start(<output-file>)---
#ifndef __ac_h_
#define __ac_h_
namespace AC {
   typedef const char* Type;
   typedef int JPType;
   struct Action {
     void **_args;
     void *_result;
     void *_target;
     void *_that;
     void (*_wrapper)(Action &);
     void *_fptr;
     inline void trigger () { _wrapper (*this); }
   };
   template <class Aspect, int Index>
   struct CFlow {
     static int &instance () {
       static int counter = 0;
       return counter;
     }
     CFlow () { instance ()++; }
     ~CFlow () { instance ()--; }
     static bool active () { return instance () > 0; }
   };

}

#endif // __ac_h_

#ifndef __forward_declarations_for_Foo__
#define __forward_declarations_for_Foo__
class Foo;
namespace AC {
   template <class JoinPoint>
   inline void invoke_Foo_Foo_a0_around (JoinPoint *tjp);
}
#endif
#include <cstdio>
using std::printf;

class Foo {
    static Foo __instance;
public:
    static Foo *aspectof () { return &__instance; }
    static Foo *aspectOf () { return &__instance; }
private:


public: template<class JoinPoint> void __a0_around (JoinPoint *tjp) {
   typedef typename JoinPoint::That __JP_That;
   typedef typename JoinPoint::Target __JP_Target;
   typedef typename JoinPoint::Result __JP_Result;

     printf ("-->\n");
     tjp->proceed ();
     printf ("<--\n");
   }
private:

};
template <class JoinPoint>
inline void AC::invoke_Foo_Foo_a0_around (JoinPoint *tjp) {
   ::Foo::aspectof()->__a0_around (tjp);
}



struct TJP__ZN4mainEiPPc {
   typedef int Result;
   typedef void That;
   typedef void Target;
   enum { ARGS = 2 };
   template <int I, int DUMMY = 0> struct Arg {
     typedef void Type;
     typedef void ReferredType;
   };
   template <int DUMMY> struct Arg<0, DUMMY> {
     typedef int Type;
     typedef int ReferredType;
   };
   template <int DUMMY> struct Arg<1, DUMMY> {
     typedef char **Type;
     typedef char **ReferredType;
   };

   AC::Action *_action;

   inline void proceed () { _action->trigger (); }
   AC::Action &action() {return *_action;}

};


inline int __exec_old_main(int argc,char **argv) {
   printf ("main() running\n");
   return 0;
}
static void __action_exec__ZN4mainEiPPc_0 (AC::Action &action) {
    *((int *)action._result) = 
__exec_old_main(*((TJP__ZN4mainEiPPc::Arg<0>::ReferredType*) 
action._args[0]), *((TJP__ZN4main
EiPPc::Arg<1>::ReferredType*) action._args[1]));
}
int main (int  arg0, char ** arg1) {
    int result;
   void *args__ZN4mainEiPPc[] = { (void*)&arg0, (void*)&arg1 };
   AC::Action tjp_action__ZN4mainEiPPc = { args__ZN4mainEiPPc, 
(void*)&result,  0,  0, __action_exec__ZN4mainEiPPc_0, 0 };
TJP__ZN4mainEiPPc tjp__ZN4mainEiPPc = {&tjp_action__ZN4mainEiPPc};

   AC::invoke_Foo_Foo_a0_around<TJP__ZN4mainEiPPc> (&tjp__ZN4mainEiPPc);
    return (int )result;

}

Foo Foo::__instance;
---end---

As you can see, all the information needed to "proceed()" the execution 
is stored in an AC::Action object (see the generated wrapper function 
for main()). The proceed() function is a member function of the 
generated JoinPoint class (here TJP__ZN4mainEiPPc). It calls trigger() 
on the Action object, which then calls __action_exec__ZN4mainEiPPc_0() 
by using a function pointer, which was stored in the Action object in 
advance.

Although there is a lot of generated source code involved, the generated 
executable becomes rather small, because of function inlining. However, 
due to the function pointer not everything can be inlined. Thus, the 
code is not optimal. Our before and after advice is implemented much 
more efficient. Do you really want to put your finger into this wound? 
This implementation was only a quick solution, which we would like to 
improve as soon as possible.

yours,

Olaf





More information about the aspectc-user mailing list