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

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() );

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.

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]

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.

----------- 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




Back to the top