[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