Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
RE: [aspectj-users] "cflow ( x()) && !cflowbelow( x()) " confuses me

> -----Original Message-----
> From: aspectj-users-admin@xxxxxxxxxxx [mailto:aspectj-users-
> admin@xxxxxxxxxxx] On Behalf Of Wes Isberg
> Sent: 26 August 2003 15:04
> To: aspectj-users@xxxxxxxxxxx
> Subject: Re: [aspectj-users] "cflow ( x()) && !cflowbelow( x()) "
confuses
> me
> 
> This confused me, too, so I'll take a shot at explaining it
> in different ways to see if one make sense.
> 
> Think of advice on join point P as in the control flow of P
> but not in the control flow below P.  To fix the pointcut, try:
> 
> from: cflow(FindExec()) && !cflowbelow( FindExec() );
>    to: FindExec() && !cflowbelow( FindExec() );
> 

The alternative that worked for me is:

cflow(FindExec()) && !cflowbelow(FindExec()) && !cflow(adviceexecution);

I'd recommend your approach instead for performance reasons.  However,
it's important to note the implications of what I've done.  As you said:
 
>    P => cflow({P})
>    P => !cflowbelow({P})
> 
> where {P} is a pointcut that matches P.

But now we have an added condition.  {P} is a pointcut that matches P,
but the join point P need not match {P}.  Rather, it could be in the
cflow of advice applied to {P}.


> Why? The programming guide focuses on when the join point P runs:
> 
>     o cflow(Pointcut)
>     The cflow pointcut picks out all join points that occur
>     between entry and exit of each join point P picked out
>     by Pointcut, including P itself.
> 
>     o cflowbelow(Pointcut)
>     The cflowbelow pointcut picks out all join points that
>     occur between entry and exit of each join point P picked
>     out by Pointcut, but not including P itself. Hence, it
>     picks out the join points below the control flow of
>     the join points picked out by Pointcut.
> 
> Also, logically this says:
> 
>    P => cflow({P})
>    P => !cflowbelow({P})
> 
> where {P} is a pointcut that matches P.

All this is fine.  The problem I'm having is that I thought that 

    P => cflow({P})
    P => !cflowbelow({P})

Held if and only if {P} is a pointcut that matches P.  

Saying 'if and only if' is a bit tighter since it specifies join points
in cflow({P}) and not in cflowbelow({P}) must match {P}.  Unfortunately,
this tighter definition does not hold when I look at the AspectJ
implementation. 

> Think about what happens.  advice runs before and after P:
> 
>     --> before [1]
>        ...
>     <-- before [1]
>     --> before [2]
>        ...
>     <-- before [2]
>     ...
>     --> join point
>        ...         // HERE -- excluded by cflowbelow(P)
>     <-- join point
>     --> after returning [2]
>        ...
>     <-- after returning [2]
>     --> after returning [1]
>        ...
>     <-- after returning [1]
> 

This demonstration gave me the idea to look at the out of band data that
AspectJ records to track whether cflow / cflowbelow is active.
Modifying the example above, I came up the following model diagram. Note
that I'm only considering first initial entry:
 
      *** Log that cflow({P}) is active, where {P} matches (join point)
>     --> before [1]
>        ...
>     <-- before [1]
>     --> before [2]
>        ...
>     <-- before [2]
>     ...
      *** Log that cflowbelow({P}) is active, where {P} matches (join
point)
>     --> (join point)
>        ...         // HERE -- excluded by cflowbelow(P)
>     <-- (join point)
      *** Log that cflowbelow({P}) is inactive, ({P} matches (join
point))
>     --> after returning [2]
>        ...
>     <-- after returning [2]
>     --> after returning [1]
>        ...
>     <-- after returning [1]
      *** Log that cflow({P}) is inactive, ({P} matches (join point))

This representation really drives home the point that there are join
points that match cflow({P}) other than those identified by {P} or
cflowbelow({P}).

> To see this, add the code below to yours, and you should
> see something like
> 
>       --> execution(ADVICE: void Cflow.ajc$before$...
>          ...
>       <-- execution(ADVICE: void Cflow.ajc$before$...
>       --> execution(int WordCounter.Find(String))
>           ...
>       <-- execution(int WordCounter.Find(String))
> 
> !cflowbelow({P}) only excludes join points at HERE, that run
> after the entry to, and before the exit of, the join point.
> (By hypothesis, advice runs at the join point P, and
> cflowbelow({P}) won't run at the join point P.)
> 
> So, should advice on {P} be considered to run within cflow({P})?
> One could argue that it should not, and that only the
> things running HERE are in the cflow of P.  But that's
> pretty much what cflowbelow({P}) is, right?  And cflow({P})
> is defined as including the join point P, so P => cflow({P}),
> and the advice should run be considered to within the
> control flow of P.
> 
> Think of cflow({P}) being true as a precondition
> of running the advice.  It would make little sense
> to run the advice before the precondition were true, but
> it would be impossible to run the advice after the
> condition were true (at HERE) but "before" the entry
> to the join point.
> 
> Should we make cflow({P}) true only at HERE for
> recursive advice, but true for "regular" advice
> throughout?  That would be very bad because it
> violates some of the principles that makes AOP
> make sense.  If cflow(P) is true for advice A,
> it should be true for advice B, C,.., even if
> B thereby advises A, and if B==A.  The pointcut
> has to match consistently, and not behave
> differently depending on the advice.  Because of
> that, there's no way to say that the advice which
> runs at P either is in the cflowbelow({P}) or is not
> in the cflow({P}), because P => cflow({P}) and
> p => !cflowbelow({P}).
> 
> This tracks something Gregor said earlier on this issue:
> 
> -----
> The two key points I want to make are that:
> 
>   - Join points, pointcuts and advice are orthogonal.
>   - Advice are on pointcuts, and pointcuts match join points.
> 
> So an advice "knows" what pointcut it is on; and poincuts "know"
> what join points they match. But there is [no*] relationship in
> the other
> direction -- pointcuts don't know what advice is on them; join points
> don't know what pointcuts match them, or what advice runs at them.
> -----
>    http://dev.eclipse.org/mhonarc/lists/aspectj-users/msg00954.html
> 
> Hope this helps...
> 
> Wes
> 
> * I added "no" because the context makes it clear that's
>    what he meant.

Gregor's comments drive home some very important points.  However, the
confusion that resulted in the email thread came from me thinking I was
looking at V1.1 documentation, when it was actually V1.0.6.  The
difficulty was compounded by the fact that V1.0.6 has undocumented
support for advice execution join points, as demonstrated in the example
I provided.  Once again I'm seeing what appears to be undocumented join
point matching.  Certainly, the example I'm looking would be outside
what I would consider normal usage of cflow/cflowbelow.  I mean, I don't
see any real purpose the example I provided.  At the same time, I was
expecting that the definition of cflow and cflowbelow would be
clarified.


> 
> ----------- links
> http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-
> home/doc/faq.html#q:recursiveentrypoints
> http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-
> home/doc/faq.html#q:infiniterecursion
> http://dev.eclipse.org/viewcvs/indextech.cgi/~checkout~/aspectj-
> home/doc/faq.html#q:advicenotrunning
> 
> ----------- code
> To see this, fix the pointcut as show above or add the
> restrictions to prevent infinite recursion:
> 
>    before(): FindCflow() && !within(Cflow) && !within(TJP+)
> 
> Then add these aspects (shorter versions of
> TraceJoinPoints.java from the FAQ):
> ----
> aspect TJPB extends TJP {
>      pointcut pc() : Cflow.FindExec();
> }
> abstract aspect TJP percflow(pc()) {
>      abstract pointcut pc();
>      StringBuffer prefix = new StringBuffer();
> 
>      void log(String s) {
>          System.out.println(s);
>      }
>      Object around() : !initialization(new(..))
>              && !preinitialization(new(..))
>              && !handler(*)
>              && (cflow(pc()) && !within(TJP+) ) {
>          prefix.append("    ");
>          log(prefix + " --> " + thisJoinPointStaticPart);
>          try {
>              return proceed();
>          } finally {
>              log(prefix + " <-- " + thisJoinPointStaticPart);
>              prefix.setLength(prefix.length()-4);
>          }
>      }
> }
> ----
> 
> 
> Donal Lafferty wrote:
> 
> > Hi,
> >
> > I have a quick question on cflow/cflowbelow that is wrecking my
brain
> > and that I cannot find an example of in the mailing list.
> >
> > Let me start with the example:
> >
> > public class WordCounterDemo
> > {
> >   public static void main(String[] args)
> >   {
> >     WordCounter wordCounter = new WordCounter();
> >     System.out.println("*** About to call Find ***");
> >     int theCount = wordCounter.Find("the");
> >     System.out.println("*** Done calling Find  ***");
> >   }
> > }
> >
> > public class WordCounter
> > {
> >   public int Find(String word)  {
> >     String newWord = word.toLowerCase();
> >     return 0;
> >   }
> > }
> >
> > public aspect Cflow {
> >   pointcut FindExec():   execution( int WordCounter.Find( String ));
> >   pointcut FindCflow():  cflow(FindExec()) && !cflowbelow(
FindExec() );
> >
> >   before(): FindCflow()
> >   {
> >     System.out.println("Before joinpoint in FindCflow pointcut, sig
" +
> >     thisJoinPointStaticPart.toLongString());
> >   }
> > }
> >
> >
> > And execution results in the following:
> >
> > *** About to call Find ***
> > Exception in thread "main" java.lang.StackOverflowError
> >
> >
> > The infinite loop can be removed by modifying the FindCflow()
pointcut
> > to remove join points encountered in the cflow of adviceexecution,
as
> > follows:
> >
> > pointcut FindCflow():  cflow(FindExec()) && !cflowbelow( FindExec()
)
> >                        && !cflow(adviceexecution());
> >
> >
> > If we consider that the only difference between cflow and cflowbelow
is
> > whether or not the join points that match explicitly the PCD's
argument
> > are included in the set of join points selected by that PCD, then
> > wouldn't the only join points that match "cflow(FindExec()) &&
> > !cflowbelow(FindExec())" be those identified in FindExec()?  And
yet,
> > join points other than those selected by FindExec() are being
executed,
> > as evidenced by the infinite loop.
> >
> > What is the bad assumption that I'm making?
> >
> >
> > DL
> >
> >
> > ________________________________________________________
> > Donal Lafferty, P.Eng., BSc. Computer Engineering
> > <http://www.dsg.cs.tcd.ie/~laffertd/>
> >
> > "Statistically, 100% of the shots you don't take, don't go in."
-Wayne
> > Gretzky
> >
> >
> > _______________________________________________
> > aspectj-users mailing list
> > aspectj-users@xxxxxxxxxxx
> > http://dev.eclipse.org/mailman/listinfo/aspectj-users
> >
> 
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/aspectj-users



Back to the top