From e1c9313a55965194e2f987d5fa5777747e068695 Mon Sep 17 00:00:00 2001
From: ehilsdal void
return type.void
return type. This will require porting of code
+ that uses the set
PCD in conjunction with after
+ returning
or around
advice.
+
+ +
now result in join points. -noweave
option is now the
-XnoWeave
option.-XnoInline
,
+ -XnoInline
,
is now supported to control some compiler behavior.
Some are have different behavior in edge cases but offer @@ -130,8 +143,12 @@ release schedule closely, however, these are the changes since the
declare
+ dominates
, that is intended to replace the "dominates"
+ clause on aspects.
+
+ But in order to support weaving into bytecode effectively, @@ -145,7 +162,7 @@ release schedule closely, however, these are the changes since the
void
return type. This will require
+ porting of code that uses the set
PCD in conjunction
+ with after-returning or around advice.First, The 1.1 compiler is implemented on top of IBM's +
First, the 1.1 compiler is implemented on top of IBM's open-source Eclipse compiler. This has two benefits: It allows us to concentrate on the AspectJ extensions to Java and let the Eclipse team worry about making sure the Java edge cases work, and it allows @@ -215,9 +240,7 @@ release schedule closely, however, these are the changes since the
This new architecture, and other changes to the compiler, allows us to implement some features that were defined in the AspectJ 1.0 - language but not implementable in the 1.1 compiler (after returning - advice on handler join points will probably be one of those - features, when handler join points are finished). It also makes + language but not implementable in the 1.1 compiler. It also makes some new features available:
..
wildcard is supported in the args
PCD. But some features of the 1.0 compiler are not supported in the 1.1 compiler:
@@ -283,8 +306,19 @@ release schedule closely, however, these are the changes since the J2SE 1.3 or later is required;.And some changes to the implementation are almost entirely + internal: +
+ +A short description of the options ajc accepts is available with - "ajc -help".
+ "ajc -help
".
@@ -331,12 +365,10 @@ release schedule closely, however, these are the changes since the
AJDE for JBuilder, AJDE for Netbeans, and AJDE for Emacs and the - AJBrowser have not changed much. They use the batch-build mode of - the new compiler. The beta compiler does not yet produce - crosscutting structure (for anything but method executions) so there are no inline - annotations in JBuilder or Emacs support and you only see a - declaration tree in the structure views. Incremental building and +
The AspectJ Browser hasn't changed much, and apart from being + distributed from Sourceforge, AJDE for JBuilder, AJDE for Netbeans, + and AJDE for Emacs haven't changed much either. They use the + batch-build mode of the new compiler. Incremental building and bytecode weaving are not available in the AJDE tools in the beta release, but will be in a future release.
@@ -437,9 +469,10 @@ release schedule closely, however, these are the changes since the advice defined in a particular aspect.preinitialization(ConstructorPattern)
will
pick out pre-initialization join points where the initializaiton
- process is entered through ConstructorPattern.
+ process is entered through
+ ConstructorPattern
.
- We strongly considered adding a pertype aspect kind to 1.1. This is somewhat motivated by the new @@ -519,7 +552,7 @@ release schedule closely, however, these are the changes since the
AspectJ 1.1 does not consider initializer execution as a +
AspectJ 1.1 does not consider initializer execution a principled join point. The collection of initializer code (the code that sets fields with initializers and the code in non-static initializer blocks) is something that makes sense only in Java @@ -563,6 +596,34 @@ release schedule closely, however, these are the changes since the must always assume incomplete object initialization, since the constructor has not yet run.
+The initializer, if any, of an inter-type field definition runs + before the class-local initializers of its target class.
+ +In AspectJ 1.0.6, such an initializer would run after the + initializers of a class but before the execution of any of its + constructor bodies. As already discussed in the sections about + initializer execution join + points and constructor + execution, the point in code between the initializers of a class + and its constructor body is not principled in bytecode. So we had a + choice of running the initializer of an inter-type field definition at + the beginning of initialization (i.e., before initializers from + the target class) or at the end (i.e., just before its called + constructor exits). We chose the former, having this pattern in mind: +
+ ++ int C.methodCount = 0; + before(C c): this(c) && execution(* *(..)) { c.methodCount++; } ++ +
We felt there would be too much surprise if a constructor called a + method (thus incrementing the method count) and then the field was + reset to zero after the constructor was done. +
+ALPHA: In the beta release of the compiler, - only one directory can be passed to the -sourceroots option. -
-The AspectJ 1.1 compiler now accepts an -injars option used to @@ -839,29 +896,29 @@ release schedule closely, however, these are the changes since the
ajc -injars myBase.jar MyTracing.java -outjar myTracedBase.jar-
No meta information is placed in the output jar file
+No meta information is placed in the output jar file.
The AspectJ 1.1 compiler now supports incremental compilation. For the final release, this will work from the various IDE plugins we - ship, but for the Alpha release, it is only supported on the + ship, but for the 1.1beta2 release, it is only supported on the command-line compiler.
When ajc is called with the -incremental option, it must also be passed a -sourceroots option specifying a directory to incrementally compile. Once the initial compile is done, ajc waits for console - input. Every time it reads a new line, (i.e., every time the user + input. Every time it reads a new line (i.e., every time the user hits return) ajc recompiles those input files that need recompiling.
some changes to classes should force re-weaving, but are not +
Some changes to classes should force re-weaving, but are not noticed
-inter-type declarations, declare parents are not tracked +
Inter-type declarations, declare parents are not tracked correctly
-XOcodeSize
is no longer necessary. We will be
+ supporting its inverse,
+ -XnoInline
in the final.
+ Many error condition in beta2 are signalled by exception. You - shouldn't be surprised to see RuntimeException("unimplemented") - produced from perfectly reasonable programs that use features we - just haven't implemented yet.
+ may see RuntimeException("unimplemented") produced from programs + that use features we just haven't implemented yet.Because we build on Eclipse, the compiler will no longer run under J2SE 1.2. - You must run the compiler (and all tools based on the compiler) - using J2SE 1.3 or later.
+ +Because we build on Eclipse, the compiler will no longer run + under J2SE 1.2. You must run the compiler (and all tools based on + the compiler) using J2SE 1.3 or later.
- inter-type constructors and default constructors conflict now -+
AspectJ 1.1 does not allow the inter-type definition of a + zero-argument constructor on a class with a visible default + constructor. So this is no longer allowed:
++ class C {} + + aspect A { + C.new() {} // was allowed in 1.0.6 + // is a "multiple definitions" conflict in 1.1 + } ++ +
In the Java Programming Language, a class defined without a
+ constructor actually has a "default" constructor that takes no
+ arguments and just calls super()
.
This default constructor is a member of the class like any other + member, and can be referenced by other classes, and has code generated + for it in classfiles. Therefore, it was an oversight that AspectJ + 1.0.6 allowed such an "overriding" inter-type constructor definition. +
- We promised to run super inits in L-R order. This was, of course, totally ludricous. We couldn't do it then and we can't do it now. - It is undefined what order they go in, apart from the other promises made in that section (interfaces with members) +In AspectJ, interfaces may have non-static members due to + inter-type declarations. Because of this, the semantics of AspectJ + defines the order that initializer code for interfaces is run. +
+ +In the semantics document for AspectJ 1.0.6, the following + promises were made about the order of this initialization: +
+ ++
+ +- a supertype is initialized before a subtype
+- initialized code runs only once
+- initializers for supertypes run in left-to-right order
+The first two properties are important and are preserved in + AspectJ 1.1, but the third property is and was ludicrous, and was + never properly implemented (and never could be) in AspectJ 1.0.6. + Consider:
+ ++ interface Top0 {} + interface Top1 {} + interface I extends Top0, Top1 {} + interface J extends Top1, Top0 {} + + class C implements I, J {} + // I says Top0's inits must run before Top1's + // J says Top1's inits must run before Top0's + + aspect A { + int Top0.i = foo("I'm in Top0"); + int Top1.i = foo("I'm in Top1"); + static int foo(String s) { + System.out.println(s); + return 37; + } + } ++ +This was simply a bug in the AspectJ specification. The correct + third rule is: +
+ +the initializers for a type's superclass are run before the + initializers for its superinterfaces. +- int C.methodCount = 0; - before(C c): this(c) && execution(* *(..)) { c.methodCount++; } - -- - this would have bizarre behavior if we didn't run initializers before constructors -
Are now void -
+In AspectJ 1.0.6, the join point for setting a field F had, as a + return type, F's type. This was "java compatible" because + field assignment in java, such as "Foo.i = 37", is in fact an + expression, and does in fact return a value, the value that the + field is assigned to. +
+ +This was never "java programmer compatible", however, largely + because programmers have absorbed the good style of rarely using an + assignment statement in a value context. Programmers typically expect + "Foo.i = 37" not to return a value, but to simply assign a value.
+ +Thus, programmers typically wanted to write something like: +
+ ++ void around(): set(int Foo.i) { + if (theSetIsAllowed()) { + proceed(); + } + } ++ +
And were confused by it being a compile-time error. They weren't + confused for long, and soon adapted to writing: +
+ ++ int around(): set(int Foo.i) { + if (theSetIsAllowed()) { + return proceed(); + } else { + return Foo.i; + } + } ++ +
But there was definitely a short disconnect.
+ +On top of that, we were never shown a convincing use-case for + returning an interesting value from a set join point. When we + revisited this issue, in fact, we realized we had a long-standing bug + in 1.0.6 dealing with the return value of pre-increment expressions + (such as ++Foo.i) that nobody had found because nobody cares about the + return value of such join points. +
-So, because it's easier to implement, and because we believe that + this is the last possibility to make the semantics more useful, we + have made set join points have a void return type in 1.1beta2. + Please complain voiceferously if you believe this is wrong, and we + can revert for the final version.
-Link to other X flags, in particular XblahBlah +
Though 1.1beta2 does not have code inlining turned on, we expect
+ that the final release will have inlining on for many cases of around
+ advice. Therefore, we are supporting the -XnoInline
+ option to indicate that no inlining of any kind should be done. This
+ is purely a compiler pragma: No program semantics (apart from stack
+ traces) will be changed by the presence or absence of this option.
+
Even in 1.0.6, the AspectJ compiler has occasionally needed to + convert the visibility of a package-level class to a public one. This + was previously done in an ad-hoc basis that took whole-program + analysis into account. With the incremental compilation model of + AspectJ 1.1, we can now specify the occasions when the compiler makes + these visibility changes. +
+ + In particular, the types used in the this
,
+ target
, and args
pointcuts are made public,
+ as are the super-types from declare parents
and the
+ exception type from declare soft
.
+
We believe the visibility changes could be avoided in the future + with various implementation tricks if they become a serious + concern, but did not encounter them as such a concern when they were + done in the 1.0.6 implementation.
+ +In Java, the + operator sometimes results in StringBuffer objects +being created, appended to, and used to generate a new String. Thus,
++class Foo { + String makeEmphatic(String s) { + return s + "!"; + } +} ++ +
is approximately the same at runtime as +
+ ++class Foo { + String makeEmphatic(String s) { + return new StringBuffer(s).append("!").toString(); + } +} ++ + +
In the design process of AspectJ 1.0.6 we didn't expose those +StringBuffer methods and constructors as join points (though we did +discuss it), but in 1.1 we do.
+ +This change is likely to affect highly wildcarded aspects, and can +do so in surprising ways. In particular: +
+ ++class A { + before(int i): call(* *(int)) && args(i) { + System.err.println("entering with " + i); + } +} ++ +
may result in a stack overflow error, since the argument to +println is really
+ ++new StringBuffer("entering with ").append(i).toString() ++ +
which has a call to StringBuffer.append(int). In such cases, it's +worth restricting your pointcut, with something like one of: +
+ ++call(* *(int)) && args(i) && !within(A) +call(* *(int)) && args(i) && !target(StringBuffer) ++ -