You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

implementation.xml 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  1. <appendix id="implementation" xreflabel="Implementation Notes">
  2. <title>Implementation Notes</title>
  3. <sect1>
  4. <title>Compiler Notes</title>
  5. <para>
  6. The initial implementations of AspectJ have all been
  7. compiler-based implementations. Certain elements of AspectJ's
  8. semantics are difficult to implement without making modifications
  9. to the virtual machine, which a compiler-based implementation
  10. cannot do. One way to deal with this problem would be to specify
  11. only the behavior that is easiest to implement. We have chosen a
  12. somewhat different approach, which is to specify an ideal language
  13. semantics, as well as a clearly defined way in which
  14. implementations are allowed to deviate from that semantics. This
  15. makes it possible to develop conforming AspectJ implementations
  16. today, while still making it clear what later, and presumably
  17. better, implementations should do tomorrow.
  18. </para>
  19. <para>
  20. According to the AspectJ language semantics, the declaration
  21. </para>
  22. <programlisting><![CDATA[
  23. before(): get(int Point.x) { System.out.println("got x"); }
  24. ]]></programlisting>
  25. <para>
  26. should advise all accesses of a field of type int and name x from
  27. instances of type (or subtype of) Point. It should do this
  28. regardless of whether all the source code performing the access
  29. was available at the time the aspect containing this advice was
  30. compiled, whether changes were made later, etc.
  31. </para>
  32. <para>
  33. But AspectJ implementations are permitted to deviate from this in
  34. a well-defined way -- they are permitted to advise only accesses
  35. in <emphasis>code the implementation controls</emphasis>. Each
  36. implementation is free within certain bounds to provide its own
  37. definition of what it means to control code.
  38. </para>
  39. <para>
  40. In the current AspectJ compiler, ajc, control of the code means
  41. having bytecode for any aspects and all the code they should
  42. affect available during the compile. This means that if some class
  43. Client contains code with the expression <literal>new
  44. Point().x</literal> (which results in a field get join point at
  45. runtime), the current AspectJ compiler will fail to advise that
  46. access unless Client.java or Client.class is compiled as well. It
  47. also means that join points associated with code in native methods
  48. (including their execution join points) cannot be advised.
  49. </para>
  50. <para>
  51. Different join points have different requirements. Method and
  52. constructor call join points can be advised only if ajc controls
  53. the bytecode for the caller. Field reference or assignment join
  54. points can be advised only if ajc controls the bytecode for the
  55. "caller", the code actually making the reference or assignment.
  56. Initialization join points can be advised only if ajc controls the
  57. bytecode of the type being initialized, and execution join points
  58. can be advised only if ajc controls the bytecode for the method or
  59. constructor body in question.
  60. The end of an exception handler is underdetermined in bytecode,
  61. so ajc will not implement after or around advice on handler join
  62. points.
  63. Similarly, ajc cannot implement around advice on initialization
  64. or preinitialization join points.
  65. In cases where ajc cannot implement advice, it will emit a
  66. compile-time error noting this as a compiler limitation.
  67. </para>
  68. <para>
  69. Aspects that are defined <literal>perthis</literal> or
  70. <literal>pertarget</literal> also have restrictions based on
  71. control of the code. In particular, at a join point where the
  72. bytecode for the currently executing object is not available, an
  73. aspect defined <literal>perthis</literal> of that join point will
  74. not be associated. So aspects defined
  75. <literal>perthis(Object)</literal> will not create aspect
  76. instances for every object unless <literal>Object</literal>is part
  77. of the compile. Similar restrictions apply to
  78. <literal>pertarget</literal> aspects.
  79. </para>
  80. <para>
  81. Inter-type declarations such as <literal>declare parents</literal>
  82. also have restrictions based on control of the code. If the
  83. bytecode for the target of an inter-type declaration is not
  84. available, then the inter-type declaration is not made on that
  85. target. So, <literal>declare parents : String implements
  86. MyInterface</literal> will not work for
  87. <literal>java.lang.String</literal> unless
  88. <literal>java.lang.String</literal> is part of the compile.
  89. </para>
  90. <para>
  91. When declaring members on interfaces, the implementation must
  92. control both the interface and the top-level implementors of
  93. that interface (the classes that implement the interface but
  94. do not have a superclass that implements the interface).
  95. You may weave these separately, but be aware that you will get
  96. runtime exceptions if you run the affected top-level classes
  97. without the interface as produced by the same ajc implementation.
  98. Any intertype declaration of an abstract method on an interface
  99. must be specified as public, you will get a compile time error
  100. message indicating this is a compiler limitation if you do not
  101. specify public. A non-abstract method declared on an interface
  102. can use any access modifier except protected. Note that this is
  103. different to normal Java rules where all members declared in
  104. an interface are implicitly public.
  105. Finally, note that one cannot define static fields or methods
  106. on interfaces.
  107. </para>
  108. <para>
  109. When declaring methods on target types, only methods declared
  110. public are recognizable in the bytecode, so methods must be
  111. declared public to be overridden in any subtype or to be called
  112. from code in a later compile using the target type as a library.
  113. </para>
  114. <para>
  115. Other AspectJ implementations, indeed, future versions of ajc, may
  116. define <emphasis>code the implementation controls</emphasis> more
  117. liberally or restrictively, so long as they comport with the Java
  118. language. For example, the <literal>call</literal> pointcut does
  119. not pick out reflective calls to a method implemented in
  120. <literal>java.lang.reflect.Method.invoke(Object, Object[])</literal>.
  121. Some suggest that the call "happens" and the call pointcut should
  122. pick it out, but the AspectJ language shouldn't anticipate what happens
  123. in code outside the control of the implementation, even when it
  124. is a a well-defined API in a Java standard library.
  125. </para>
  126. <para>
  127. The important thing to remember is that core concepts of AspectJ,
  128. such as the join point, are unchanged, regardless of which
  129. implementation is used. During your development, you will have to
  130. be aware of the limitations of the ajc compiler you're using, but
  131. these limitations should not drive the design of your aspects.
  132. </para>
  133. </sect1>
  134. <sect1>
  135. <title>Bytecode Notes</title>
  136. <sect2 id="the-class-expression-and-string" xreflabel="the-class-expression-and-string">
  137. <title>The .class expression and String +</title>
  138. <para> The java language form <literal>Foo.class</literal> is
  139. implemented in bytecode with a call to
  140. <literal>Class.forName</literal> guarded by an exception
  141. handler catching a <literal>ClassNotFoundException</literal>.
  142. </para>
  143. <para> The java language + operator, when applied to String
  144. arguments, is implemented in bytecode by calls to
  145. <literal>StringBuffer.append</literal>.
  146. </para>
  147. <para> In both of these cases, the current AspectJ compiler
  148. operates on the bytecode implementation of these language
  149. features; in short, it operates on what is really happening rather
  150. than what was written in source code. This means that there may
  151. be call join points to <literal>Class.forName</literal> or
  152. <literal>StringBuffer.append</literal> from programs that do not,
  153. at first glance, appear to contain such calls:
  154. </para>
  155. <programlisting><![CDATA[
  156. class Test {
  157. void main(String[] args) {
  158. System.out.println(Test.class); // calls Class.forName
  159. System.out.println(args[0] + args[1]); // calls StringBuffer.append
  160. }
  161. }
  162. ]]></programlisting>
  163. <para>In short, the join point model of the current AspectJ
  164. compiler considers these as valid join points.
  165. </para>
  166. </sect2>
  167. <sect2 id="the-handler-join-point" xreflabel="the-handler-join-point">
  168. <title>The Handler join point</title>
  169. <para>The end of exception handlers cannot reliably be found in Java
  170. bytecode. Instead of removing the handler join point entirely, the
  171. current AspectJ compiler restricts what can be done with the handler
  172. join point:
  173. </para>
  174. <itemizedlist>
  175. <listitem>After and around advice cannot apply to handler
  176. join points.</listitem>
  177. <listitem>The control flow of a handler join point cannot be
  178. detected. </listitem>
  179. </itemizedlist>
  180. <para>
  181. The first of these is relatively straightforward. If any piece of
  182. after advice (returning, throwing, or "finally") would normally
  183. apply to a handler join point, it will not in code output by the
  184. current AspectJ compiler. A compiler warning is generated whenever
  185. this is detected to be the case. Before advice is allowed.
  186. </para>
  187. <para> The second is that the control flow of a handler join point
  188. is not picked out. For example, the following pointcut
  189. </para>
  190. <programlisting><![CDATA[
  191. cflow(call(void foo()) || handler(java.io.IOException))
  192. ]]></programlisting>
  193. <para> will capture all join points in the control flow of a call to
  194. <literal>void foo()</literal>, but it will <emphasis>not</emphasis>
  195. capture those in the control flow of an
  196. <literal>IOException</literal> handler. It is equivalent to
  197. <literal>cflow(call(void foo()))</literal>. In general,
  198. <literal>cflow(handler(<replaceable>Type</replaceable>))</literal>
  199. will not pick out any join points, the one exception to this is join points
  200. that occur during the execution of any before advice on the handler.
  201. </para>
  202. <para> This does not restrict programs from placing before advice on
  203. handlers inside <emphasis>other</emphasis> control flows. This
  204. advice, for example, is perfectly fine:
  205. </para>
  206. <programlisting><![CDATA[
  207. before(): handler(java.io.IOException) && cflow(void parse()) {
  208. System.out.println("about to handle an exception while parsing");
  209. }
  210. ]]></programlisting>
  211. <para>
  212. A source-code implementation of AspectJ (such as AspectJ 1.0.6) is
  213. able to detect the endpoint of a handler join point, and as such
  214. will likely have fewer such restrictions.
  215. </para>
  216. </sect2>
  217. <sect2 id="initializers-and-inter-type-constructors" xreflabel="initializers-and-inter-type-constructors">
  218. <title>Initializers and Inter-type Constructors</title>
  219. <para>
  220. The code for Java initializers, such as the assignment to the
  221. field d in
  222. </para>
  223. <programlisting><![CDATA[
  224. class C {
  225. double d = Math.sqrt(2);
  226. }
  227. ]]></programlisting>
  228. <para>
  229. are considered part of constructors by the time AspectJ gets ahold
  230. of bytecode. That is, the assignment of d to the square root of
  231. two happens <emphasis>inside</emphasis> the default constructor of
  232. C.
  233. </para>
  234. <para>
  235. Thus inter-type constructors will not necessarily run a target
  236. type's initialization code. In particular, if the inter-type
  237. constructor calls a super-constructor (as opposed to a
  238. <literal>this</literal> constructor), the target type's
  239. initialization code will <emphasis>not</emphasis> be run when that
  240. inter-type constructor is called.
  241. </para>
  242. <programlisting><![CDATA[
  243. aspect A {
  244. C.new(Object o) {} // implicitly calls super()
  245. public static void main(String[] args) {
  246. System.out.println((new C() ).d); // prints 1.414...
  247. System.out.println((new C(null)).d); // prints 0.0
  248. }
  249. ]]></programlisting>
  250. <para>
  251. It is the job of an inter-type constructor to do all the required
  252. initialization, or to delegate to a <literal>this</literal>
  253. constructor if necessary.
  254. </para>
  255. </sect2>
  256. </sect1>
  257. <sect1>
  258. <title>Annotation-style Notes</title>
  259. <para>Writing aspects in annotation-style is subject to the same
  260. bytecode limitations since the binary aspects take the same
  261. form and are woven in the same way. However, the implementation
  262. differences (e.g., the mechanism for implementing around advice)
  263. may be apparent at runtime. See the documentation on annotation-style
  264. for more information.
  265. </para>
  266. </sect1>
  267. <sect1>
  268. <title>Summary of implementation requirements</title>
  269. <para>
  270. This summarizes the requirements of our implementation of AspectJ.
  271. For more details, see the relevant sections of this guide.
  272. </para>
  273. <itemizedlist spacing="compact">
  274. <listitem>
  275. <para>The invoking code must be under the control of ajc
  276. for the following join points:</para>
  277. <itemizedlist spacing="compact">
  278. <listitem>call join point</listitem>
  279. <listitem>get join point</listitem>
  280. <listitem>set join point</listitem>
  281. </itemizedlist>
  282. </listitem>
  283. <listitem>
  284. <para>The declaring/target code must be under the control of ajc
  285. for the following join points and inter-type declarations:</para>
  286. <itemizedlist spacing="compact">
  287. <listitem>execution join point</listitem>
  288. <listitem>adviceexecution join point</listitem>
  289. <listitem>handler join point</listitem>
  290. <listitem>initialization join point</listitem>
  291. <listitem>preinitialiaztion join point</listitem>
  292. <listitem>staticinitialization join point</listitem>
  293. <listitem>perthis aspect</listitem>
  294. <listitem>pertarget aspect</listitem>
  295. <listitem>declare parents</listitem>
  296. <listitem>declare method or field (see interface caveats below)</listitem>
  297. </itemizedlist>
  298. </listitem>
  299. <listitem>
  300. <para>Implementation Caveats</para>
  301. <itemizedlist spacing="compact">
  302. <listitem>
  303. <para>The initialization and preinitialization join points
  304. do not support around advice</para>
  305. </listitem>
  306. <listitem>
  307. <para>The handler join point does not support...</para>
  308. <itemizedlist spacing="compact">
  309. <listitem>after advice</listitem>
  310. <listitem>around advice</listitem>
  311. <listitem>cflow(handler(..))</listitem>
  312. </itemizedlist>
  313. </listitem>
  314. <listitem>
  315. <para>Declaring members on an interface in an aspect affects only
  316. the topmost implementing classes the implementation controls.</para>
  317. </listitem>
  318. <listitem>
  319. <para>cflow and cflowbelow pointcuts work within a single thread.</para>
  320. </listitem>
  321. <listitem>
  322. <para>
  323. Runtime <literal>ClassCastException</literal> may result
  324. from supplying a supertype of the actual type as an argument
  325. to proceed(..) in around advice.</para>
  326. </listitem>
  327. </itemizedlist>
  328. </listitem>
  329. </itemizedlist>
  330. </sect1>
  331. </appendix>