Bug 546167 - Support after(), around(), cflow() for handler() pointcut
Summary: Support after(), around(), cflow() for handler() pointcut
Status: NEW
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.9.2   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-04-05 22:34 EDT by Alexander Kriegisch CLA
Modified: 2020-04-21 14:00 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Alexander Kriegisch CLA 2019-04-05 22:34:24 EDT
When trying to answer SO question https://stackoverflow.com/q/55537926/1082681, I noticed that the handler() pointcut only supports before() advice. In order to solve the given problem I would need something like cflow(handler()), though. I can write and compile that, but the corresponding advice never triggers. Probably this is a consequence of handler() being incompatible with after() and around(), i.e. with the way this pointcut designator is currently implemented. I am aware of the fact that bytecode generation for handlers looks quite strange when decompiling, using labels and jumps etc. Maybe this is why it is so difficult to fully implement handler() so as to identify when the control flow leaves the handler.

But for what it is worth, I am creating a ticket anyway. Maybe there is an idea how this could be implemented, maybe it is possible and "just" difficult. At least we can discuss it and Andy or whoever can explain why it might be impossible to implement for everyone to understand better.
Comment 1 Alexander Kriegisch CLA 2020-01-01 00:02:22 EST
I would appreciate some feedback. Thank you very much and Happy New Year 2020. :-)
Comment 2 Andrew Clement CLA 2020-04-21 00:53:17 EDT
The reason this was never added was there is no recorded end for an exception handler. The exception table lists "if exception X happens between NNN and NNN then jump to JJJ". After JJJ it is not recorded where the end of the exception catch block is. It may be possible to take a 'reasonable guess' from common bytecode patterns from javac and JDT.
Comment 3 Alexander Kriegisch CLA 2020-04-21 01:35:32 EDT
Could the end of handler block n be inferred from by the jump address of block n+1? Look at this example:

------------------------------------------------------------

System.out.println("before try-catch");

try {
  doSomething()
  // if SpecialException, jump to 'handler1'
  // if Exception, jump to 'handler2'
  // if no exception, jump to 'after'
}
catch (SpecialException e) {
  handler1:
  logSomething();
}
catch (Exception e) {
  handler2:
  logSomething();
}

after:
System.out.println("after try-catch");

------------------------------------------------------------

Handler #1 ends at the instruction before label 'handler2', doesn't it?

Handler #2 ends at the instruction before label 'after', doesn't it?

Of course the labels don't exist in the code, but the jump targets do.

It has been a while since I last looked at disassembled byte code, so I do not remember how exactly this is represented. But the logical structure should be like that. Maybe you can utilise strategies from Fernflower (the very good Java decompiler built into IntelliJ IDEA) in order to dermine the logical structure of the code and then use the information acquired in order to implement after/around for handler pointcuts.
Comment 4 Alexander Kriegisch CLA 2020-04-21 01:38:11 EDT
Oh BTW, I did not think this through for nested exception handlers or even know how they are represented in byte code, but maybe there is a way to get this done recursively. Having said that, I am aware of the fact that probably the nested structure is represented in a "flattened out" linear structure in the byte code with lots more ugly jumps.
Comment 5 Andrew Clement CLA 2020-04-21 14:00:25 EDT
> Handler #1 ends at the instruction before label 'handler2', doesn't it?
> Handler #2 ends at the instruction before label 'after', doesn't it?

Obviously that is the first set of assumptions I would look at. Maybe that is right, I haven't read enough examples to verify. I need to check output of JDT and javac which can differ. I would not want to build something fragile here. I think things are more straightforward than when the first round of engineering was done because in those days subroutines were allowed. Without those, it is more linear.