]> source.dussan.org Git - aspectj.git/commitdiff
333274: more tests and fixes: nested @Around advice with proceed
authorAndy Clement <aclement@pivotal.io>
Tue, 19 Feb 2019 20:25:01 +0000 (12:25 -0800)
committerAndy Clement <aclement@pivotal.io>
Tue, 19 Feb 2019 20:25:01 +0000 (12:25 -0800)
13 files changed:
org.aspectj.matcher/src/main/java/org/aspectj/weaver/Advice.java
org.aspectj.matcher/src/main/java/org/aspectj/weaver/Shadow.java
org.aspectj.matcher/src/main/java/org/aspectj/weaver/ShadowMunger.java
runtime/src/main/java/org/aspectj/lang/ProceedingJoinPoint.java
runtime/src/main/java/org/aspectj/runtime/internal/AroundClosure.java
runtime/src/main/java/org/aspectj/runtime/reflect/JoinPointImpl.java
tests/src/test/java/org/aspectj/systemtest/ajc1611/Ajc1611Tests.java
tests/src/test/java/org/aspectj/systemtest/ajc193/Ajc193Tests.java
tests/src/test/resources/org/aspectj/systemtest/ajc1611/ajc1611.xml
tests/src/test/resources/org/aspectj/systemtest/ajc190/ajc190.xml
tests/src/test/resources/org/aspectj/systemtest/ajc193/ajc193.xml
weaver/src/main/java/org/aspectj/weaver/bcel/BcelAdvice.java
weaver/src/main/java/org/aspectj/weaver/bcel/BcelShadow.java

index d6c8ea87f39c745d3ba47975052456e68da7e918..cd786e7246edffcff277ce948698013ec2ad2a3b 100644 (file)
@@ -83,6 +83,10 @@ public abstract class Advice extends ShadowMunger {
                ret.concreteAspect = inAspect;
                return ret;
        }
+       
+       public boolean isAroundAdvice() {
+               return attribute.getKind() == AdviceKind.Around;
+       }
 
        public static Advice makeSoftener(World world, Pointcut entry, TypePattern exceptionType, ResolvedType inAspect,
                        IHasSourceLocation loc) {
index 587d19c1564caff902c174809536dcdd190bb359..1a8ed529056e020617c1188d5e08e92029004b95 100644 (file)
@@ -46,7 +46,8 @@ public abstract class Shadow {
        private ResolvedMember resolvedSignature;
        protected final Shadow enclosingShadow;
        protected List<ShadowMunger> mungers = Collections.emptyList();
-
+       protected boolean needAroundClosureStacking = false;
+       
        public int shadowId = nextShadowID++; // every time we build a shadow, it gets a new id
 
        // ----
@@ -628,6 +629,20 @@ public abstract class Shadow {
        /** Actually implement the (non-empty) mungers associated with this shadow */
        private void implementMungers() {
                World world = getIWorld(); 
+               needAroundClosureStacking = false;
+               int annotationStyleWithAroundAndProceedCount = 0;
+               for (ShadowMunger munger: mungers) {
+                       if (munger.getDeclaringType()!= null && 
+                               munger.getDeclaringType().isAnnotationStyleAspect() &&
+                               munger.isAroundAdvice() &&
+                               munger.bindsProceedingJoinPoint()) {
+                               annotationStyleWithAroundAndProceedCount++;
+                               if (annotationStyleWithAroundAndProceedCount>1) {
+                                       needAroundClosureStacking = true;
+                                       break;
+                               }
+                       }
+               }
                for (ShadowMunger munger : mungers) {
                        if (munger.implementOn(this)) {
                                world.reportMatch(munger, this);
index c07d7e8e7c6b86733766aeea38909a2a7d86770a..a0e49becc915fd27128d41f0038ed0dd32a15c2f 100644 (file)
@@ -303,5 +303,13 @@ public abstract class ShadowMunger implements PartialOrder.PartialComparable, IH
        // }
        // newShadowMunger.binaryFile = null;
        // }
+       
+       public boolean bindsProceedingJoinPoint() {
+               return false;
+       }
+       
+       public boolean isAroundAdvice() {
+               return false;
+       }
 
 }
index d75aa4df4bcd27cd46c55b37484a50d44b09fb14..ac85681efe597a690d7d605f87d8357d6171de6a 100644 (file)
@@ -29,6 +29,19 @@ public interface ProceedingJoinPoint extends JoinPoint {
      */
     void set$AroundClosure(AroundClosure arc);
 
+    /**
+     * The joinpoint needs to know about its closure so that proceed can delegate to closure.run().
+     * This internal method should not be called directly, and won't be visible to the end-user when
+     * packed in a jar (synthetic method). This should maintain a stack of closures as multiple around
+     * advice with proceed are targeting a joinpoint and the stack will need to be unwound when
+     * exiting nested advice. Passing a non null arc indicates a push, passing null indicates a pop.
+     *
+     * @param arc the around closure to associate with this joinpoint
+     */
+     default void stack$AroundClosure(AroundClosure arc) {
+        throw new UnsupportedOperationException();
+     }
+
     /**
      * Proceed with the next advice or target method invocation
      *
index 41c165149fdd32e4972a16dc9a62647b291dacee..c7a9acc1e872e8c802e98b65e88d463b7b7b10df 100644 (file)
@@ -65,6 +65,21 @@ public abstract class AroundClosure {
         return jp;
     }
 
+    /**
+     * This method is called to implicitly associate the closure with the joinpoint
+     * as required for @AJ aspect proceed()
+     * 
+     * @param flags indicating whether this/target found at joinpoint and bound
+     * @return the associated ProceedingJoinPoint
+     */
+    public ProceedingJoinPoint linkStackClosureAndJoinPoint(int flags) {
+        //TODO is this cast safe ?
+        ProceedingJoinPoint jp = (ProceedingJoinPoint)state[state.length-1];
+        jp.stack$AroundClosure(this);
+        this.bitflags = flags;
+        return jp;
+    }
+
     /**
      * This method is called to implicitly associate the closure with the joinpoint
      * as required for @AJ aspect proceed()
@@ -79,4 +94,10 @@ public abstract class AroundClosure {
         this.bitflags = flags;
         return jp;
     }
+
+    public void unlink() {
+       ProceedingJoinPoint jp = (ProceedingJoinPoint)state[state.length-1];
+       jp.stack$AroundClosure(null);
+    }
+
 }
index 69bff1e3c97b56ed3a0f102bab63df566bbe6040..0263ee84171f5c6584571e571fba549cc4cb666a 100644 (file)
@@ -13,6 +13,8 @@
 
 package org.aspectj.runtime.reflect;
 
+import java.util.Stack;
+
 import org.aspectj.lang.JoinPoint;
 import org.aspectj.lang.ProceedingJoinPoint;
 import org.aspectj.lang.Signature;
@@ -134,47 +136,73 @@ class JoinPointImpl implements ProceedingJoinPoint {
                return staticPart.toLongString();
        }
 
-       // To proceed we need a closure to proceed on
-       private AroundClosure arc;
+       // To proceed we need a closure to proceed on. Generated code
+       // will either be using arc or arcs but not both. arcs being non-null
+       // indicates it is in use (even if an empty stack)
+       private AroundClosure arc = null;       
+       private Stack<AroundClosure> arcs = null;
 
        public void set$AroundClosure(AroundClosure arc) {
                this.arc = arc;
        }
 
+       public void stack$AroundClosure(AroundClosure arc) {
+               // If input parameter arc is null this is the 'unlink' call from AroundClosure
+               if (arcs == null) {
+                       arcs = new Stack<AroundClosure>();
+               }
+               if (arc==null) {
+                       this.arcs.pop();
+               } else {
+                       this.arcs.push(arc);
+               }
+       }
+
        public Object proceed() throws Throwable {
                // when called from a before advice, but be a no-op
-               if (arc == null)
-                       return null;
-               else
-                       return arc.run(arc.getState());
+               if (arcs == null) {
+                       if (arc == null) {
+                               return null;
+                       } else {
+                               return arc.run(arc.getState());
+                       }
+               } else {
+                       return arcs.peek().run(arcs.peek().getState());                 
+               }
        }
 
        public Object proceed(Object[] adviceBindings) throws Throwable {
                // when called from a before advice, but be a no-op
-               if (arc == null)
+               AroundClosure ac = null;
+               if (arcs == null) {
+                       ac = arc;
+               } else {
+                       ac = arcs.peek();
+               }
+               
+               if (ac == null) {
                        return null;
-               else {
-
+               } else {
                        // Based on the bit flags in the AroundClosure we can determine what to
                        // expect in the adviceBindings array. We may or may not be expecting
                        // the first value to be a new this or a new target... (see pr126167)
-                       int flags = arc.getFlags();
+                       int flags = ac.getFlags();
                        boolean unset = (flags & 0x100000) != 0;
                        boolean thisTargetTheSame = (flags & 0x010000) != 0;
                        boolean hasThis = (flags & 0x001000) != 0;
                        boolean bindsThis = (flags & 0x000100) != 0;
                        boolean hasTarget = (flags & 0x000010) != 0;
                        boolean bindsTarget = (flags & 0x000001) != 0;
-
+       
                        // state is always consistent with caller?,callee?,formals...,jp
-                       Object[] state = arc.getState();
-
+                       Object[] state = ac.getState();
+       
                        // these next two numbers can differ because some join points have a this and
                        // target that are the same (eg. call) - and yet you can bind this and target
                        // separately.
-
+       
                        // In the state array, [0] may be this, [1] may be target
-
+       
                        int firstArgumentIndexIntoAdviceBindings = 0;
                        int firstArgumentIndexIntoState = 0;
                        firstArgumentIndexIntoState += (hasThis ? 1 : 0);
@@ -202,8 +230,8 @@ class JoinPointImpl implements ProceedingJoinPoint {
                                                // This previous variant doesn't seem to cope with only binding target at a joinpoint
                                                // which has both this and target. It forces you to supply this even if you didn't bind
                                                // it.
-//                                             firstArgumentIndexIntoAdviceBindings = (hasThis ? 1 : 0) + 1;
-//                                             state[hasThis ? 1 : 0] = adviceBindings[hasThis ? 1 : 0];
+       //                                              firstArgumentIndexIntoAdviceBindings = (hasThis ? 1 : 0) + 1;
+       //                                              state[hasThis ? 1 : 0] = adviceBindings[hasThis ? 1 : 0];
                                                
                                                int targetPositionInAdviceBindings = (hasThis && bindsThis) ? 1 : 0;
                                                firstArgumentIndexIntoAdviceBindings = ((hasThis&&bindsThis)?1:0)+((hasTarget&&bindsTarget&&!thisTargetTheSame)?1:0);
@@ -213,12 +241,12 @@ class JoinPointImpl implements ProceedingJoinPoint {
                                        // leave state[0]/state[1] alone, they are OK
                                }
                        }
-
+       
                        // copy the rest across
                        for (int i = firstArgumentIndexIntoAdviceBindings; i < adviceBindings.length; i++) {
                                state[firstArgumentIndexIntoState + (i - firstArgumentIndexIntoAdviceBindings)] = adviceBindings[i];
                        }
-
+       
                        // old code that did this, didnt allow this/target overriding
                        // for (int i = state.length-2; i >= 0; i--) {
                        // int formalIndex = (adviceBindings.length - 1) - (state.length-2) + i;
@@ -226,7 +254,7 @@ class JoinPointImpl implements ProceedingJoinPoint {
                        // state[i] = adviceBindings[formalIndex];
                        // }
                        // }
-                       return arc.run(state);
+                       return ac.run(state);
                }
        }
 
index d974123ee0bd0e0dffae204477ac543b2e2f37c6..8f44cfa59732f3a35557af608bf3c456dacff99b 100644 (file)
@@ -103,17 +103,17 @@ public class Ajc1611Tests extends org.aspectj.testing.XMLBasedAjcTestCase {
                runTest("pr328840");
        }
 
-       // public void testAnnoStyleAdviceChain_333274() {
-       // runTest("anno style advice chain");
-       // }
-       //
-       // public void testAnnoStyleAdviceChain_333274_2() {
-       // runTest("code style advice chain");
-       // }
-       //
-       // public void testAnnoStyleAdviceChain_333274_3() {
-       // runTest("code style advice chain - no inline");
-       // }
+        public void testAnnoStyleAdviceChain_333274() {
+                runTest("anno style advice chain");
+        }
+       
+        public void testAnnoStyleAdviceChain_333274_2() {
+                runTest("code style advice chain");
+        }
+       
+        public void testAnnoStyleAdviceChain_333274_3() {
+                runTest("code style advice chain - no inline");
+        }
 
        // ---
 
index 1199db2625944bf1981f08128b045dd8aec21d2c..6a52df395867ea75d681d7bc1effa2478419362e 100644 (file)
@@ -5,7 +5,7 @@
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *******************************************************************************/
-package org.aspectj.systemtest.ajc193;
+package org.aspectj.systemtest.ajc193; 
 
 import java.io.File;
 
@@ -18,9 +18,13 @@ import junit.framework.Test;
 
 /**
  * @author Andy Clement
- */
+ */ 
 public class Ajc193Tests extends XMLBasedAjcTestCaseForJava10OrLater {
 
+       public void testNestedAroundProceed() {
+               runTest("nested around proceed");
+       }
+
        public void testDeclareMixinOverweavingControl() {
                runTest("overweaving decm - control");
        }
index beb9229241f5e0b99eb853b8112f8cc97483eef0..1f42edfd63bfe28f42d929f9fd564f94bc9a5b30 100644 (file)
   </ajc-test>
   
   <ajc-test dir="bugs1611/pr333274" title="code style advice chain">
-  <compile files="ma2/Annotation1.java  ma2/aspect1/Aspect1.java  ma2/aspect3/Aspect3.java ma2/Main.java ma2/Precedence.java" options="-1.5 "/>
+  <compile files="ma2/Annotation1.java  ma2/aspect1/Aspect1.java  ma2/aspect3/Aspect3.java ma2/Main.java ma2/Precedence.java" options="-1.5 -XnoInline"/>
   <run class="ma2.Main">
   <stdout>
   <line text="&gt;In Aspect1"/>
index d6507daceae1c89a17fe9421ba1d590c67ae2127..2936888cba233d5863702239d36dcea7fada2c06 100644 (file)
@@ -77,8 +77,8 @@
   </ajc-test>
 
   <ajc-test dir="bugs190/modules/fff" title="compile module including aspects">
-    <compile files="module-info.java pkg/Demo.java otherpkg/Azpect.java" modulepath="$runtime" outjar="demomodule.jar" options="-1.9"/>
-    <run modulepath="$runtime:demomodule.jar" module="demo/pkg.Demo">
+    <compile files="module-info.java pkg/Demo.java otherpkg/Azpect.java" modulepath="$runtimemodule" outjar="demomodule.jar" options="-1.9"/>
+    <run modulepath="$runtimemodule:demomodule.jar" module="demo/pkg.Demo">
       <stdout>
       <line text="Azpect running"/>
       <line text="Demo running"/>
index 7d64d493eb1a24dfdf829053b21bdaf39197a6ef..2a4be40f8220cd18fe22fada6075b1ef5a6273a7 100644 (file)
@@ -2,6 +2,42 @@
 
 <suite>
 
+    <ajc-test dir="bugs193/333274" vm="1.8" title="nested around proceed">
+        <compile files="ma/aspect2/Aspect2.java,ma/aspect2/Annotation2.java,ma/aspect3/Aspect3.java,ma/aspect3/Annotation3.java,ma/Precedence.java,ma/Main.java,ma/aspect1/Aspect1.java,ma/aspect1/Annotation1.java" options="-showWeaveInfo -1.8 -XnoInline">
+               <message kind="weave" text="Join point 'method-execution(int ma.Main$Dummy.retryTranslateAndTimeLimited())' in Type 'ma.Main$Dummy' (Main.java:16) advised by around advice from 'ma.aspect3.Aspect3' (Aspect3.java:11)"/>
+               <message kind="weave" text="Join point 'method-execution(int ma.Main$Dummy.retryTranslateAndTimeLimited())' in Type 'ma.Main$Dummy' (Main.java:16) advised by around advice from 'ma.aspect2.Aspect2' (Aspect2.java:11)"/>
+               <message kind="weave" text="Join point 'method-execution(int ma.Main$Dummy.retryTranslateAndTimeLimited())' in Type 'ma.Main$Dummy' (Main.java:16) advised by around advice from 'ma.aspect1.Aspect1' (Aspect1.java:12)"/>
+        </compile>
+        <!-- 
+        >In Aspect1
+>In Aspect2
+>In Aspect3
+Method call
+<In Aspect3
+<In Aspect2
+=In Aspect1
+Method call
+<In Aspect1
+ -->
+        <run class="ma.Main">
+               <stdout>
+               <line text="&gt;In Aspect1"/>
+               <line text="&gt;In Aspect2"/>
+               <line text="&gt;In Aspect3"/>
+               <line text="Method call"/>
+               <line text="&lt;In Aspect3"/>
+               <line text="&lt;In Aspect2"/>
+               <line text="=In Aspect1"/>
+               <line text="&gt;In Aspect2"/>
+               <line text="&gt;In Aspect3"/>
+               <line text="Method call"/>
+               <line text="&lt;In Aspect3"/>
+               <line text="&lt;In Aspect2"/>
+                       <line text="&lt;In Aspect1"/>
+               </stdout>
+        </run>
+    </ajc-test>
+
     <ajc-test dir="bugs193/543657" vm="1.8" title="overweaving decm - control">
         <compile files="MoodIndicator.java,Code1.java" options="-showWeaveInfo -1.8">
                <message kind="weave" text="Mixing interface 'MoodIndicator$Moody' (MoodIndicator.java) into type 'Code1' (Code1.java)"/>
index d22b17d121cdc07d25711bb812322bed7296423f..924e6e10c90912d81b5185e430e463ca24520ec8 100644 (file)
@@ -76,7 +76,17 @@ class BcelAdvice extends Advice {
                super(attribute, pointcut, simplify(attribute.getKind(), adviceSignature));
                this.concreteAspect = concreteAspect;
        }
-
+       
+       public boolean bindsProceedingJoinPoint() {
+               UnresolvedType[] parameterTypes = signature.getParameterTypes();
+               for (int i=0;i<parameterTypes.length;i++) {
+                       if (parameterTypes[i].equals(UnresolvedType.PROCEEDING_JOINPOINT)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+       
        /**
         * A heavyweight BcelMethod object is only required for around advice that will be inlined. For other kinds of advice it is
         * possible to save some space.
@@ -603,6 +613,7 @@ class BcelAdvice extends Advice {
                                                        } else {
                                                                previousIsClosure = true;
                                                                il.append(closureInstantiation.copy());
+                                                               shadow.closureVarInitialized = true;
                                                        }
                                                }
                                        } else if ("Lorg/aspectj/lang/JoinPoint$StaticPart;".equals(getSignature().getParameterTypes()[i]
index c93a0f26e1eee97cd02e77d200cbcf68a9e5e49c..6d0cb4f601246e6a6c7efe258ceee924b8f5db33 100644 (file)
@@ -70,6 +70,7 @@ import org.aspectj.weaver.patterns.NotPointcut;
 import org.aspectj.weaver.patterns.OrPointcut;
 import org.aspectj.weaver.patterns.ThisOrTargetPointcut;
 
+
 /*
  * Some fun implementation stuff:
  * 
@@ -881,6 +882,12 @@ public class BcelShadow extends Shadow {
        private Map<ResolvedType, AnnotationAccessVar> withinAnnotationVars = null;
        private Map<ResolvedType, AnnotationAccessVar> withincodeAnnotationVars = null;
        private boolean allArgVarsInitialized = false;
+       
+       // If in annotation style and the relevant advice is using PJP then this will 
+       // be set to true when the closure variable is initialized - if it gets set
+       // (which means link() has been called) then we will need to call unlink()
+       // after the code has been run.
+       boolean closureVarInitialized = false;
 
        @Override
        public Var getThisVar() {
@@ -2836,6 +2843,8 @@ public class BcelShadow extends Shadow {
                }
        }
 
+       BcelVar aroundClosureInstance = null;
+
        public void weaveAroundClosure(BcelAdvice munger, boolean hasDynamicTest) {
                InstructionFactory fact = getFactory();
 
@@ -2934,21 +2943,66 @@ public class BcelShadow extends Shadow {
                        bitflags |= 0x000001;
                }
 
+               closureVarInitialized = false;
+               
                // ATAJ for @AJ aspect we need to link the closure with the joinpoint instance
                if (munger.getConcreteAspect() != null && munger.getConcreteAspect().isAnnotationStyleAspect()
                                && munger.getDeclaringAspect() != null && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()) {
+
+                       aroundClosureInstance = genTempVar(AjcMemberMaker.AROUND_CLOSURE_TYPE);
+                       closureInstantiation.append(fact.createDup(1));
+                       aroundClosureInstance.appendStore(closureInstantiation, fact);
+                       
                        // stick the bitflags on the stack and call the variant of linkClosureAndJoinPoint that takes an int
                        closureInstantiation.append(fact.createConstant(Integer.valueOf(bitflags)));
-                       closureInstantiation.append(Utility.createInvoke(getFactory(), getWorld(),
-                                       new MemberImpl(Member.METHOD, UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"),
-                                                       Modifier.PUBLIC, "linkClosureAndJoinPoint", String.format("%s%s", "(I)", "Lorg/aspectj/lang/ProceedingJoinPoint;"))));
+                       if (needAroundClosureStacking) {
+                               closureInstantiation.append(Utility.createInvoke(getFactory(), getWorld(),
+                                               new MemberImpl(Member.METHOD, UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"),
+                                                               Modifier.PUBLIC, "linkStackClosureAndJoinPoint", String.format("%s%s", "(I)", "Lorg/aspectj/lang/ProceedingJoinPoint;"))));
+                               
+                       } else {
+                               closureInstantiation.append(Utility.createInvoke(getFactory(), getWorld(),
+                                               new MemberImpl(Member.METHOD, UnresolvedType.forName("org.aspectj.runtime.internal.AroundClosure"),
+                                                               Modifier.PUBLIC, "linkClosureAndJoinPoint", String.format("%s%s", "(I)", "Lorg/aspectj/lang/ProceedingJoinPoint;"))));                          
+                       }
+
                }
 
                InstructionList advice = new InstructionList();
                advice.append(munger.getAdviceArgSetup(this, null, closureInstantiation));
 
                // invoke the advice
-               advice.append(munger.getNonTestAdviceInstructions(this));
+               InstructionHandle tryUnlinkPosition  = advice.append(munger.getNonTestAdviceInstructions(this));
+               
+               if (needAroundClosureStacking) {
+                       // Call AroundClosure.unlink() in a 'finally' block
+                       if (munger.getConcreteAspect() != null && munger.getConcreteAspect().isAnnotationStyleAspect()
+                                       && munger.getDeclaringAspect() != null
+                                       && munger.getDeclaringAspect().resolve(world).isAnnotationStyleAspect()
+                                       && closureVarInitialized) {
+                               
+                               // Call unlink when 'normal' flow occurring
+                               aroundClosureInstance.appendLoad(advice, fact);
+                               InstructionHandle unlinkInsn = advice.append(Utility.createInvoke(getFactory(), getWorld(), new MemberImpl(Member.METHOD, UnresolvedType
+                                               .forName("org.aspectj.runtime.internal.AroundClosure"), Modifier.PUBLIC, "unlink",
+                                               "()V")));
+                               
+                               InstructionHandle jumpOverHandler = advice.append(InstructionConstants.NOP);
+                               
+                               // Call unlink in finally block
+                               InstructionHandle handlerStart = advice.append(InstructionConstants.POP);
+                               aroundClosureInstance.appendLoad(advice, fact);
+                               advice.append(Utility.createInvoke(getFactory(), getWorld(), new MemberImpl(Member.METHOD, UnresolvedType
+                                               .forName("org.aspectj.runtime.internal.AroundClosure"), Modifier.PUBLIC, "unlink",
+                                               "()V")));
+                               advice.append(InstructionConstants.ACONST_NULL);
+                               advice.append(InstructionConstants.ATHROW);
+                               InstructionHandle jumpTarget = advice.append(InstructionConstants.NOP);
+                               jumpOverHandler.setInstruction(InstructionFactory.createBranchInstruction(Constants.GOTO, jumpTarget));
+                               enclosingMethod.addExceptionHandler(tryUnlinkPosition, unlinkInsn, handlerStart, null/* ==finally */, false);
+                       }       
+               }
+               
                advice.append(returnConversionCode);
                if (getKind() == Shadow.MethodExecution && linenumber > 0) {
                        advice.getStart().addTargeter(new LineNumberTag(linenumber));