diff options
author | ehilsdal <ehilsdal> | 2003-12-02 19:31:52 +0000 |
---|---|---|
committer | ehilsdal <ehilsdal> | 2003-12-02 19:31:52 +0000 |
commit | 9f8fdd6e73ae4995d195cc5637307ee7b5d9b057 (patch) | |
tree | 052207e2a17b62ba31efbe65ca95b19828489ee0 /docs/progGuideDB/implementation.xml | |
parent | 4880b54e69fcd225590fce7079a84d2b17a6ee62 (diff) | |
download | aspectj-9f8fdd6e73ae4995d195cc5637307ee7b5d9b057.tar.gz aspectj-9f8fdd6e73ae4995d195cc5637307ee7b5d9b057.zip |
Fix for Bugzilla 37899: Document or address limitations on handler pointcut/joinpoints
* changed "Implementation Limitations" to "Implementation Notes" inside ProgGuide
* added section on bytecode limitations, headed by handler issues.
Diffstat (limited to 'docs/progGuideDB/implementation.xml')
-rw-r--r-- | docs/progGuideDB/implementation.xml | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/docs/progGuideDB/implementation.xml b/docs/progGuideDB/implementation.xml new file mode 100644 index 000000000..314c574f9 --- /dev/null +++ b/docs/progGuideDB/implementation.xml @@ -0,0 +1,178 @@ +<appendix id="implementation" xreflabel="Implementation Notes"> + + <title>Implementation Notes</title> + +<sect1> + <title>Compiler Notes</title> + + <para> + The initial implementations of AspectJ have all been + compiler-based implementations. Certain elements of AspectJ's + semantics are difficult to implement without making modifications + to the virtual machine, which a compiler-based implementation + cannot do. One way to deal with this problem would be to specify + only the behavior that is easiest to implement. We have chosen a + somewhat different approach, which is to specify an ideal language + semantics, as well as a clearly defined way in which + implementations are allowed to deviate from that semantics. This + makes it possible to develop conforming AspectJ implementations + today, while still making it clear what later, and presumably + better, implementations should do tomorrow. + </para> + + <para> + According to the AspectJ language semantics, the declaration + </para> + +<programlisting><![CDATA[ + before(): get(int Point.x) { System.out.println("got x"); } +]]></programlisting> + + <para> + should advise all accesses of a field of type int and name x from + instances of type (or subtype of) Point. It should do this + regardless of whether all the source code performing the access + was available at the time the aspect containing this advice was + compiled, whether changes were made later, etc. + </para> + + <para> + But AspectJ implementations are permitted to deviate from this in + a well-defined way -- they are permitted to advise only accesses + in <emphasis>code the implementation controls</emphasis>. Each + implementation is free within certain bounds to provide its own + definition of what it means to control code. + </para> + + <para> + In the current AspectJ compiler, ajc, control of the code means + having bytecode for any aspects and all the code they should + affect available during the compile. This means that if some class + Client contains code with the expression <literal>new + Point().x</literal> (which results in a field get join point at + runtime), the current AspectJ compiler will fail to advise that + access unless Client.java or Client.class is compiled as well. It + also means that join points associated with code in native methods + (including their execution join points) cannot be advised. + </para> + + <para> + Different join points have different requirements. Method and + constructor call join points can be advised only if ajc controls + the bytecode for the caller. Field reference or assignment join + points can be advised only if ajc controls the bytecode for the + "caller", the code actually making the reference or assignment. + Initialization join points can be advised only if ajc controls the + bytecode of the type being initialized, and execution join points + can be advised only if ajc controls the bytecode for the method or + constructor body in question. + The end of an exception handler is underdetermined in bytecode, + so ajc will not implement after or around advice on handler join + points. + Similarly, ajc cannot implement around advice on initialization + or preinitialization join points. + In cases where ajc cannot implement advice, it will emit a + compile-time error noting this as a compiler limitation. + </para> + + <para> + Aspects that are defined <literal>perthis</literal> or + <literal>pertarget</literal> also have restrictions based on + control of the code. In particular, at a join point where the + bytecode for the currently executing object is not available, an + aspect defined <literal>perthis</literal> of that join point will + not be associated. So aspects defined + <literal>perthis(Object)</literal> will not create aspect + instances for every object unless <literal>Object</literal>is part + of the compile. Similar restrictions apply to + <literal>pertarget</literal> aspects. + </para> + + <para> + Inter-type declarations such as <literal>declare parents</literal> + also have restrictions based on control of the code. If the + bytecode for the target of an inter-type declaration is not + available, then the inter-type declaration is not made on that + target. So, <literal>declare parents : String implements + MyInterface</literal> will not work for + <literal>java.lang.String</literal> unless + <literal>java.lang.String</literal> is part of the compile. + </para> + + <para> + Other AspectJ implementations, indeed, future versions of ajc, may + define <emphasis>code the implementation controls</emphasis> more + liberally or restrictively. + </para> + + <para> + The important thing to remember is that core concepts of AspectJ, + such as the join point, are unchanged, regardless of which + implementation is used. During your development, you will have to + be aware of the limitations of the ajc compiler you're using, but + these limitations should not drive the design of your aspects. + </para> +</sect1> + +<sect1> + <title>Bytecode Notes</title> + + <para>The end of exception handlers cannot reliably be found in Java + bytecode. Instead of removing the handler join point entirely, the + current AspectJ compiler restricts what can be done with the handler + join point: + </para> + + <itemizedlist> + <listitem>After and around advice cannot apply to handler + join points.</listitem> + + <listitem>The control flow of a handler join point cannot be + detected. </listitem> + </itemizedlist> + + <para> + The first of these is relatively straightforward. If any piece of + after advice (returning, throwing, or "finally") would normally + apply to a handler join point, it will not in code output by the + current AspectJ compiler. A compiler warning is generated whenever + this is detected to be the case. Before advice is allowed. + </para> + + <para> The second is that the control flow of a handler join point + is not picked out. For example, the following pointcut + </para> + +<programlisting><![CDATA[ + cflow(call(void foo()) || handler(java.io.IOException)) +]]></programlisting> + + <para> will capture all join points in the control flow of a call to + <literal>void foo()</literal>, but it will <emphasis>not</emphasis> + capture those in the control flow of an + <literal>IOException</literal> handler. It is equivalent to + <literal>cflow(call(void foo()))</literal>. In general, + <literal>cflow(handler(<replaceable>Type</replaceable>))</literal> + will pick out no join points. + </para> + + <para> This does not restrict programs from placing before advice on + handlers inside <emphasis>other</emphasis> control flows. This + advice, for example, is perfectly fine: + </para> + +<programlisting><![CDATA[ + before(): handler(java.io.IOException) && cflow(void parse()) { + System.out.println("about to handle an exception while parsing"); + } +]]></programlisting> + + <para> + A source-code implementation of AspectJ (such as AspectJ 1.0.6) is + able to detect the endpoint of a handler join point, and as such + will likely have fewer such restrictions. + </para> + +</sect1> + +</appendix> |