[aspectc-user] 2 questions: "within" a function; call vs execution context

Olaf Spinczyk Olaf.Spinczyk at informatik.uni-erlangen.de
Thu Nov 15 22:28:19 CET 2007


Hi Mike,

a lot of questions ...

The within() pointcut functions matches all code join-points 'within' a
specific lexical scope. Its argument has to be a name-pointcut, i.e.
something static and *not*, for instance, execution(...). Therefore, you
can simply use ...

within("float CircleArea(float)") && call(...)

... to match certains calls that are located within the CircleArea
function. BTW, the syntax that you used (within("classname")) is the
same as within ("% classname::%(...)") plus join-points located in the
initialization of class members, e.g. static members. Also note that the
argument of within() can be a (name-)pointcut expression of arbitrary
complexity.

Question #2 points out a problem of the current AspectC++ join-point
API. For a call join-point signature() returns the name of the target
function. The name of the scope that contains the call is not available.
Today, I think providing a signature for code join-points was not a very
clever design decision. It would be better to provide the signature of
name join-points that are related to a specific code join-point. In the
case of a call this would be the signatures of the source *and* the
target function.

Best regards,

Olaf


Mike Mortensen schrieb:
> I think these might both be simple questions, but both are involve
> practical, everyday types of things to do with aspects that I thought
> I could
> do and then ran into problems with!
>
> Suppose I have a Circle class, that has 2 methods, getArea and
> getPerimeter,
> that call a function -- getPI() -- which I use to decide how precise
> the math
> value PI should be, like this:
>
> double getPI() {
>   return 3.1415;
> }
>
> class Circle {
>  ...
>  double radius, x, y;
> public:
>     double getArea() {
>       return radius * radius * getPI();
>    }
>    double getPerimeter() {
>       return 2.0 * radius * getPI();
>    }
>
> };
>
> If I want to advise (i.e. trace or whatever) the calls to getPI()
> within the Circle
> class,I can do that easily using within:
>
> aspect AdvisePI {
>
>   pointcut call_pi_within_Circle() =
>      call("% getPI()") && within("Circle");
>
>   advice call_pi_within_Circle() : before()
>   {
>      cerr << "AOP: About to call PI within Circle class, JoinPoint="
>           << JoinPoint::signature() << endl;
>   }
> };
>
> Thus, *any* call to getPI() from within the Circle class gets traced.
>
> Here's my question -- what if I also have a procedural version of
> getArea, like this:
>
> float CircleArea(float r)
> {
>   return r * r * getPI();
> }
>
> and I would like to trace getPI()  but only when it's called within
> the CircleArea function.
> I know I could use 'cflow', but that is extra overhead (i.e. it
> advises *all* calls to getPI and
> then at run time checks to see if it's within the execution of
> CircleArea).
> Also, my real goal is to advise *all* function calls within some other
> function (like CircleArea)
> for tracing.  But I don't want *every* function in the system to have
> advise that at run time
> checks cflow.
>
> I've tried advising getPI within Circle area a couple of ways:
>
>  pointcut call_pi_within_CircleArea1() =
>      call("% getPI()") && within("% %::CircleArea(...)");
>
>   pointcut call_pi_within_CircleArea2() =
>      call("% getPI()") && within("CircleArea");
>
> and also tried using within in conjuction with a named pointcut, but
> the weave says this is illegal:
>   pointcut CircleAreaExec() = execution("% CircleArea(...)");
>   pointcut call_pi_within_CircleArea3() =
>      call("% getPI()") && within(CircleAreaExec());  /* ILLEGAL !  */
>
> To summarize:
>
>    QUESTION #1: Can I use within (or other static mechanism, not
> cflow) to trace all calls to getPI()
>      within another function, rather than within a class or namespace?
>
>
> For question #2, consider calls to getPI in the circle class and
> within the CircleArea() function.
> Whether I use a call pointcut or execution pointcut, when I print out
> 'JoinPoint::signature()'
> within the advice, it is:
>   double getPI()
>
> This is fine...but what I really want is the name of the caller.  It
> would be nice to print out
> which function was about to call getPI(), but I can't seem to do that,
> even when using the calling
> pointcut so that I'm 'intercepting' the calls within the caller rather
> than at the execution.
> I know that with the calling context I can get the object invoking the
> method -- but can I get
> the name of the method about to call getPI()?
> To summarize:
>
>   QUESTION #2:  When using a call pointcut where multiple methods call
> that joinpoint, is there
>       some way to print out not the matching function being called
> (getPI) but instead the
>       actual caller's name -- Circle::getArea() or
> Circle::getPerimeter()?
>
> Thanks!
> -Mike
>
> PS  I'm attaching my aspect file and code in case it helps clarify any
> of these questions...
>
> ------------------------------------------------------------------------
>
>
> #include <cassert>
> #include <string>
> #include <iostream>
>
> using namespace std;
>
> double getPI() {
>    return 3.1415;
> }
>
> class Circle
> {
>    protected:
>     double x,y;
>     double radius;
>    public:
>     Circle() :  x(0),y(0),radius(0) {}
>     Circle(double _x, double _y, double _r) : 
>         x(_x), y(_y), radius(_r) {}
>     double getArea() {
>        return radius * radius * getPI();
>     }
>     double getPerimeter() {
>        return 2.0 * radius * getPI();
>     }
>     std::string getName() { 
>         // std::stringstream ss;
> 	//ss << " Circle (" << x << "," << y << ") r: " << radius << " ";
> 	//return ss.str();
>       char buffer[50];
>       sprintf(buffer," Circle (%g , %g r: %g) ", x,y,radius);
>       return buffer; 
>     }
> };
>
> std::ostream& operator <<(std::ostream& os, Circle *circle_ptr)
> {
>    os << circle_ptr->getName() ;
>    return os;
> }
>
> float CircleArea(float r)
> {
>    return r * r * getPI();
> }
>
> float CircleArea3(float r)
> {
>    return r * r * 3.0; //intentionally difference from CircleArea
> }
>
> int main()
> {
>    int y;
>
>    float z;
>    z = CircleArea(3);
>    cerr << " Area of circle(3) is " << z << endl;
>    z = CircleArea(2.5);
>    cerr << " Area of circle(2.5) is " << z << endl;
>    z = CircleArea(3);
>    cerr << " Area of circle(3) is " << z << endl;
>    cerr << endl;
>
>    cerr << endl;
>
>    z = CircleArea3(3);
>    cerr << " Area of circle3(3) is " << z << endl;
>    z = CircleArea3(2.5);
>    cerr << " Area of circle3(2.5) is " << z << endl;
>    z = CircleArea3(3);
>    cerr << " Area of circle3(3) is " << z << endl;
>    cerr << endl;
>
>    Circle *c1 = new Circle(3,3,5);
>    Circle *c2 = new Circle(1,1,1);
>    Circle *c3 = new Circle(1,1,1);
>
>    double a;
>    a = c1->getArea();
>    cerr << " area of c1 is " << a << endl;
>    a = c2->getArea();
>    cerr << " area of c2 is " << a << endl;
>    a = c1->getArea();
>    cerr << " area of c1 is " << a << endl;
>    a = c3->getArea();
>    cerr << " area of c3 is " << a << endl;
>    Circle c4(5,5,5);
>    a = c4.getArea();
>    cerr << " area of c4 is " << a << endl;
>    cerr << endl;
>
>    return 0;
> }
>   
> ------------------------------------------------------------------------
>
> #ifndef ADVISE_PI
> #define ADVISE_PI
>
> #include <string>
> #include <iostream>
>
> using namespace std;
>
> aspect AdvisePI {
>
>    pointcut call_pi_within_Circle() =
>       call("% getPI()") && within("Circle");
>
>    pointcut exec_pi() = execution("% getPI()");
>
>    pointcut call_pi_within_CircleArea1() =
>       call("% getPI()") && within("% %::CircleArea(...)");
>
>    pointcut call_pi_within_CircleArea2() =
>       call("% getPI()") && within("CircleArea");
>
> /*    pointcut CircleAreaExec() = execution("% CircleArea(...)");
>     pointcut call_pi_within_CircleArea3() = 
>       call("% getPI()") && within(CircleAreaExec());  // ILLEGAL!
> */
>
>    pointcut call_pi_within_CircleArea() = call_pi_within_CircleArea1() ||
> 					  call_pi_within_CircleArea2();
>
>    advice call_pi_within_CircleArea() : before()
>    {
>       cerr << "AOP: About to call PI within CircleArea function, JoinPoint="
> 	   << JoinPoint::signature() << endl;
>    }
>
>    advice call_pi_within_Circle() : before()
>    {
>       cerr << "AOP: About to call PI within Circle class, JoinPoint="
> 	   << JoinPoint::signature() << endl;
>    }
>
>    advice exec_pi() : before()
>    {
>       cerr << "AOP: About to exec PI, JoinPoint="
> 	   << JoinPoint::signature() << endl;
>    }
>
>
> };
> #endif
>   
> ------------------------------------------------------------------------
>
> _______________________________________________
> aspectc-user mailing list
> aspectc-user at aspectc.org
> http://www.aspectc.org/mailman/listinfo/aspectc-user
>   




More information about the aspectc-user mailing list