Bug 74952 - before,after !(cflow(within(Trace*))) prints nothing
Summary: before,after !(cflow(within(Trace*))) prints nothing
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.2   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 1.2.1   Edit
Assignee: Adrian Colyer CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2004-09-24 11:04 EDT by Chi-Hua Chen CLA
Modified: 2004-10-22 06:43 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Chi-Hua Chen CLA 2004-09-24 11:04:58 EDT
Reference: "cflow(within(C)) vs (within(C)||cflowbelow(within(C)) in
aspectj-users mailing list.

The aspect TraceClass below doesn't print any message when the pointcut is
defined to "!cflow(within(Trace*))". The other defintion "!(within(Trace*) ||
cflowbelow(within(Trace*)))" works fine. Wes Isberg in his reply explained that
cflow should never be used alone but he thought "there is a bug or two in here"

class SomeClass 
{
    static public void main (String [] args) {
    }
} // SomeClass

aspect TraceClass {

    // members
    static private int level = 0;

    static private void offset() {
        int i;
        for (i = 0; i < level; ++i) {
            System.out.print("  ");
        }
    } // offset

    pointcut pc() : 
        !cflow(within(Trace*))
//        !(within(Trace*) || cflowbelow(within(Trace*)))
        ;
    before () : pc() {
        offset();
        System.out.println("-> " + thisJoinPoint);
        ++level;
    }
    after  () : pc() {
        --level;
        offset();
        System.out.println("<- " + thisJoinPoint);
    }
} // TraceClass

In order to try to figure out what is happening within TraceClass, I added a
second aspect, TraceTrace, just to trace TraceClass.

aspect TraceTrace {

    // members
    static private int level = 0;

    static private void offset() {
        int i;
        for (i = 0; i < level; ++i) {
            System.out.print("  ");
        }
    } // offset

    pointcut pc() : within(TraceClass);
    before () : pc() {
        offset();
        System.out.println("=> " + thisJoinPoint);
        ++level;
    }
    after  () : pc() {
        --level;
        offset();
        System.out.println("<= " + thisJoinPoint);
    }
} // TraceTrace

Here is what TraceTrace prints when TraceClass uses "!cflow(within(Trace*))"

=> staticinitialization(TraceClass.<clinit>)
  => set(int TraceClass.level)
  <= set(int TraceClass.level)
  => preinitialization(TraceClass())
    => initialization(TraceClass())
      => execution(TraceClass())
      <= execution(TraceClass())
    <= initialization(TraceClass())
  <= staticinitialization(TraceClass.<clinit>)

The after advice is not executed for preinitialization.
Comment 1 Chi-Hua Chen CLA 2004-09-24 11:06:48 EDT
I use 

AspectJ Compiler 1.2 built on Friday May 21, 2004 at 15:06:22 GMT

and 

java version "1.4.2_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_01-b06)
Java HotSpot(TM) Client VM (build 1.4.2_01-b06, mixed mode)
Comment 2 Andrew Clement CLA 2004-10-21 09:08:24 EDT
Ok.  There is a real bug here.  It is to do with how cflow entry is applied to
preinitialization join points.  We manage the cflow with a counter at various
join points we will check this counter and if the number is >0 we are in a
particular cflow.  We apply logic at the top of the cflow to increment and
decrement the counter around the join point that matches the pointcut inside the
cflow() statement.  This example program produces a class file that doesn't
always decrement the counter when it should.  

The problem is actually because when working with the preinitialization shadow
it is in an odd state in that it contains a branch that jumps off the end of the
shadow, when in fact all branches inside it should jump to the end of the
shadow.  Because it doesn't exit normally, we fail to apply the 'counter
decrement' logic correctly.

The fix is to attach a NOP to the end of the preinitialization shadow before
weaving - the branches inside the shadow then jump to this NOP rather than off
the end of the shadow.  We can then apply the 'counter decrement' logic (which
is actually woven in as after() advice).

Without the fix, the output is only a few lines long, missing all sorts of join
points.  With the fix in place, the program outputs this :)

=> staticinitialization(TraceClass.<clinit>)
  => set(int TraceClass.level)
  <= set(int TraceClass.level)
  => preinitialization(TraceClass())
  <= preinitialization(TraceClass())
  => initialization(TraceClass())
    => execution(TraceClass())
    <= execution(TraceClass())
  <= initialization(TraceClass())
<= staticinitialization(TraceClass.<clinit>)
=> execution(ADVICE: void TraceClass.ajc$before$TraceClass$1$346234(JoinPoint))
  => call(void TraceClass.offset())
    => execution(void TraceClass.offset())
      => get(int TraceClass.level)
      <= get(int TraceClass.level)
    <= execution(void TraceClass.offset())
  <= call(void TraceClass.offset())
  => get(PrintStream java.lang.System.err)
  <= get(PrintStream java.lang.System.err)
  => call(java.lang.StringBuffer(String))
  <= call(java.lang.StringBuffer(String))
  => call(StringBuffer java.lang.StringBuffer.append(Object))
  <= call(StringBuffer java.lang.StringBuffer.append(Object))
  => call(String java.lang.StringBuffer.toString())
  <= call(String java.lang.StringBuffer.toString())
  => call(void java.io.PrintStream.println(String))
-> staticinitialization(WhatsGoingOn.<clinit>)
  <= call(void java.io.PrintStream.println(String))
  => get(int TraceClass.level)
  <= get(int TraceClass.level)
  => set(int TraceClass.level)
  <= set(int TraceClass.level)
<= execution(ADVICE: void TraceClass.ajc$before$TraceClass$1$346234(JoinPoint))
=> execution(ADVICE: void TraceClass.ajc$after$TraceClass$2$346234(JoinPoint))
  => get(int TraceClass.level)
  <= get(int TraceClass.level)
  => set(int TraceClass.level)
  <= set(int TraceClass.level)
  => call(void TraceClass.offset())
    => execution(void TraceClass.offset())
      => get(int TraceClass.level)
      <= get(int TraceClass.level)
    <= execution(void TraceClass.offset())
  <= call(void TraceClass.offset())
  => get(PrintStream java.lang.System.err)
  <= get(PrintStream java.lang.System.err)
  => call(java.lang.StringBuffer(String))
  <= call(java.lang.StringBuffer(String))
  => call(StringBuffer java.lang.StringBuffer.append(Object))
  <= call(StringBuffer java.lang.StringBuffer.append(Object))
  => call(String java.lang.StringBuffer.toString())
  <= call(String java.lang.StringBuffer.toString())
  => call(void java.io.PrintStream.println(String))
<- staticinitialization(WhatsGoingOn.<clinit>)
  <= call(void java.io.PrintStream.println(String))
<= execution(ADVICE: void TraceClass.ajc$after$TraceClass$2$346234(JoinPoint))
=> execution(ADVICE: void TraceClass.ajc$before$TraceClass$1$346234(JoinPoint))
  => call(void TraceClass.offset())
    => execution(void TraceClass.offset())
      => get(int TraceClass.level)
      <= get(int TraceClass.level)
    <= execution(void TraceClass.offset())
  <= call(void TraceClass.offset())
  => get(PrintStream java.lang.System.err)
  <= get(PrintStream java.lang.System.err)
  => call(java.lang.StringBuffer(String))
  <= call(java.lang.StringBuffer(String))
  => call(StringBuffer java.lang.StringBuffer.append(Object))
  <= call(StringBuffer java.lang.StringBuffer.append(Object))
  => call(String java.lang.StringBuffer.toString())
  <= call(String java.lang.StringBuffer.toString())
  => call(void java.io.PrintStream.println(String))
-> execution(void WhatsGoingOn.main(String[]))
  <= call(void java.io.PrintStream.println(String))
  => get(int TraceClass.level)
  <= get(int TraceClass.level)
  => set(int TraceClass.level)
  <= set(int TraceClass.level)
<= execution(ADVICE: void TraceClass.ajc$before$TraceClass$1$346234(JoinPoint))
=> execution(ADVICE: void TraceClass.ajc$after$TraceClass$2$346234(JoinPoint))
  => get(int TraceClass.level)
  <= get(int TraceClass.level)
  => set(int TraceClass.level)
  <= set(int TraceClass.level)
  => call(void TraceClass.offset())
    => execution(void TraceClass.offset())
      => get(int TraceClass.level)
      <= get(int TraceClass.level)
    <= execution(void TraceClass.offset())
  <= call(void TraceClass.offset())
  => get(PrintStream java.lang.System.err)
  <= get(PrintStream java.lang.System.err)
  => call(java.lang.StringBuffer(String))
  <= call(java.lang.StringBuffer(String))
  => call(StringBuffer java.lang.StringBuffer.append(Object))
  <= call(StringBuffer java.lang.StringBuffer.append(Object))
  => call(String java.lang.StringBuffer.toString())
  <= call(String java.lang.StringBuffer.toString())
  => call(void java.io.PrintStream.println(String))
<- execution(void WhatsGoingOn.main(String[]))
  <= call(void java.io.PrintStream.println(String))
<= execution(ADVICE: void TraceClass.ajc$after$TraceClass$2$346234(JoinPoint))

Fix checked in, waiting on build.
Comment 3 Andrew Clement CLA 2004-10-22 06:43:23 EDT
Fix available:

BUILD COMPLETE -  build.387
Date of build: 10/21/2004 21:05:26
Time to build: 128 minutes 30 seconds
Last changed: 10/21/2004 16:41:04
Latest good AspectJ jar available at:
download.eclipse.org/technology/ajdt/dev/aspectj-DEVELOPMENT.jar