[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