Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-dev] change in runtime execution order

I presume you don't want me just to answer that "Its undefined - so
you can't rely on it and I can change it whenever I like".

As you have asked on aspectj-dev, I will give you more to go on. 
Heres todays story, but be aware I could change it all tomorrow:

Here is the highly scientific advice sorting algorithm from M2:

Collections.sort(
	shadowMungerList,
	new Comparator() {
		public int compare(Object o1, Object o2) {
			return o1.toString().compareTo(o2.toString());
		}
	});

Here is an example program:

class X {
  public static void main(String[]argv) {
  }
}

aspect A {
  before(): execution(* main(..)) && within(*) { }
}
aspect B {
  before(): execution(* main(..)) && within(*){ }
}

Here is the other of the shadow mungers after the sort (these are
examples of the toString() of a munger):

(before: ((within(*) && execution(* main(..))) &&
persingleton(A))->void A.ajc$before$A$1$ce209d4e())
(before: ((within(*) && execution(* main(..))) &&
persingleton(B))->void B.ajc$before$B$1$ce209d4e())


Here is the advice sorting algorithm for M3:

Collections.sort(
	shadowMungerList,
        new Comparator() {
	  public int compare(Object o1, Object o2) {
	    ShadowMunger sm1 = (ShadowMunger)o1;
	    ShadowMunger sm2 = (ShadowMunger)o2;
	    if (sm1.getSourceLocation()==null) return
(sm2.getSourceLocation()==null?0:1);
	    if (sm2.getSourceLocation()==null) return -1;			
	    return (sm2.getSourceLocation().getOffset()-sm1.getSourceLocation().getOffset());
	}
});

On the same program, the order is now:

(before: ((within(*) && execution(* main(..))) &&
persingleton(B))->void B.ajc$before$B$1$ce209d4e())
(before: ((within(*) && execution(* main(..))) &&
persingleton(A))->void A.ajc$before$A$1$ce209d4e())

The reason it was changed was because of @AJ syntax.  Consider the
case where two pieces of advice *come from the same type* and hit the
same join point.  The first point where they will differ in their
toString() is in the name of the advice method generated
(ajc$blahblahblah) - now in code style the name is generated by the
compiler and is prefix "ajc$" advicekind "before$" sourcetype "A$"
advice number within file "1$" hashcode of pointcut string "ce209d4e".
 And so a sort on toString effectively sorts on the advice number
within the file, if you have two source files, it will happen to sort
by file then advice number within the file (since the type name
happens to appear in the perclause when the munger is toString()'d)

Now, in @AJ style, the *user* controls the name of the advice, so
sorting by toString() is a little more unpredictable for multiple
pieces of advice from the same file  (Seeing as how two pieces of
advice could have the same name and just differ in terms of
parameters)
So to get back to some kind of at least predictable order (for the
sake of writing testcases that expect certain output...), we switched
to an algorithm that sorts by source location (actually offset within
the file).  I could change it again to sort by source file name, then
by source location which might get us back to the old ordering...  But
if we just worked because you'd called your aspects A and B and they'd
fail if they were renamed in the opposite alphabetical order then that
wouldn't be ideal...

It seems that todays choice of algorithm has flushed out
(unfortunately for Ron) some issues to do with precedence being more
important than anticipated.

Look out for the M4 version which sorts advice based on how many times
you've used the letter 'p' in your advice body.

;)


Back to the top