Bug 533038 - Around advice breaks LTW hot swap
Summary: Around advice breaks LTW hot swap
Status: NEW
Alias: None
Product: AspectJ
Classification: Tools
Component: LTWeaving (show other bugs)
Version: 1.8.11   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-03-29 02:45 EDT by Michał Karpiński CLA
Modified: 2018-03-29 16:15 EDT (History)
1 user (show)

See Also:


Attachments
ltw-bug Maven project (3.16 KB, application/zip)
2018-03-29 02:45 EDT, Michał Karpiński CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michał Karpiński CLA 2018-03-29 02:45:08 EDT
Created attachment 273354 [details]
ltw-bug Maven project

When using AROUND advices, LTW agent weaves the class only once (when it is loaded). On HOT SWAP (class redefinition) it wont weave the class with debug message 'cannot weave <class name>'. The reason for that is that WeavingAdaptor.couldWeave(String, byte[]) method returns 'false' for such class because the hashmap WeavingAdaptor.generatedClasses contains that class's name as it was generated, which is not the case.

HOT SWAP works fine with LTW as long as you stay away from AROUND advice.

You may reproduce this issue using the attached project:
 1. import the project in Eclipse as 'Maven Project', 
 2. run com.test.Test class as 'Java Application' (it will run for 20s),
 3. edit the Test.test method and enter different message and save the class.

Expected result: the program should change the message
Actual result: the message is not updated, there is a debug message debug cannot weave 'com.test.Test'

In com.test.TestAspect class I placed some other aspects just to prove that in general HOT SWAP with LTW works fine - if you comment out @Around part and uncomment @Before and @After parts, hot swapping works like a dream.
Comment 1 Michał Karpiński CLA 2018-03-29 04:37:13 EDT
This issue also occurs on 1.8.13.
Comment 2 Andrew Clement CLA 2018-03-29 14:47:19 EDT
If I run it in this way, how is it using loadtime weaving? I just imported it, converted it to an AspectJ project. I then ran Test and the console update changed as I edited the text (that was on latest ADJT that includes 1.9.0 but I can't think any changes have been made in 1.9.0 that would affect it). But it isn't using LTW in this case.
Comment 3 Andrew Clement CLA 2018-03-29 14:53:13 EDT
Ok I ran it in debug mode with -javaagent:<pathto>/aspectjweaver.jar at step (2) and aspectjrt.jar on classpath and it is doing as reported.
Comment 4 Andrew Clement CLA 2018-03-29 15:49:52 EDT
Made a simple change to tidy up the generated classes if a redefinition is imminent but it doesn't fix things. The hotswap box will complain about a modifier change, need to dig into why it is changing a modifier on redefinition.
Comment 5 Andrew Clement CLA 2018-03-29 16:00:59 EDT
With my changes discussed previously this will work if you specify -XnoInline in weaver options. For the 'first weave' it is deciding to generate a closure (i.e. not inline), for the 'second weave' (redefinition) it was deciding to inline. This produces differing advice infrastructure signatures:

Without -XnoInline:

javap -private Test (first load):
public class com.test.Test {
  private static org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0;
  public com.test.Test();
  public void test();
  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
  static {};
  static final void test_aroundBody0(com.test.Test, org.aspectj.lang.JoinPoint);
  private static void ajc$preClinit();
}

javap -private Test (post redefinition):
public class com.test.Test {
  private static org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0;
  public com.test.Test();
  public void test();
  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
  static {};
  private static final void test_aroundBody0(com.test.Test, org.aspectj.lang.JoinPoint);
  private static final void test_aroundBody1$advice(com.test.Test, org.aspectj.lang.JoinPoint, com.test.TestAspect, org.aspectj.lang.ProceedingJoinPoint);
  private static void ajc$preClinit();
}

So need to dig into why it thought it could inline on second attempt, although possibly the -XnoInline workaround makes the initial changes I've done useful.
Comment 6 Andrew Clement CLA 2018-03-29 16:15:57 EDT
The difference appears to be that when deciding whether to inline it checks whether the aspect being applied has been woven. On the initial run that says NO (the aspect isn't woven, so it can be inlined), on the second run it says YES.  I think the question it is trying to ask is "Have you been modified by advice?" which should be answering NO in both cases but instead it is asking the question "Have you been through the weaver?". That's a bigger thing than I want to tackle right now so I think i'll go with my changes and -XnoInline enables folks to try it out.