Bug 445395 - ClassCastException: ConstantUtf8 cannot be cast to ConstantInvokeDynamic
Summary: ClassCastException: ConstantUtf8 cannot be cast to ConstantInvokeDynamic
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Runtime (show other bugs)
Version: 1.8.2   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 1.8.3   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-09-29 14:54 EDT by Jose San Leandro CLA
Modified: 2014-10-07 19:35 EDT (History)
2 users (show)

See Also:


Attachments
A Maven project showing the ClassCastException when running tests. (32.53 KB, application/x-zip-compressed)
2014-09-29 14:54 EDT, Jose San Leandro CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Jose San Leandro CLA 2014-09-29 14:54:43 EDT
Created attachment 247455 [details]
A Maven project showing the ClassCastException when running tests.

Hi,

When compiling a simple project [1] using aspectj-maven-plugin, I get the error below. It only happens when the pointcut gets applied. If I make the pointcut intercept nothing [2], it compiles successfully.

[ERROR] Failed to execute goal org.codehaus.mojo:aspectj-maven-plugin:1.7:compile (default) on project lambda-control-flow-poc: AJC compiler errors:
[ERROR] error at (no source information available)
[ERROR] /home/chous/github/LambdaControlFlowPoC/src/main/java/org/acmsl/pocs/lambdafor/ControlFlowDriver.java:0::0 Internal compiler error: java.lang.ClassCastException: org.aspectj.apache.bcel.classfile.ConstantUtf8 cannot be cast to org.aspectj.apache.bcel.classfile.ConstantInvokeDynamic at org.aspectj.apache.bcel.generic.InvokeDynamic.getSignature(InvokeDynamic.java:108)
[ERROR] abort ABORT -- (ClassCastException) org.aspectj.apache.bcel.classfile.ConstantUtf8 cannot be cast to org.aspectj.apache.bcel.classfile.ConstantInvokeDynamic
[ERROR] org.aspectj.apache.bcel.classfile.ConstantUtf8 cannot be cast to org.aspectj.apache.bcel.classfile.ConstantInvokeDynamic
[ERROR] java.lang.ClassCastException: org.aspectj.apache.bcel.classfile.ConstantUtf8 cannot be cast to org.aspectj.apache.bcel.classfile.ConstantInvokeDynamic
[ERROR] at org.aspectj.apache.bcel.generic.InvokeDynamic.getSignature(InvokeDynamic.java:108)
[ERROR] at org.aspectj.apache.bcel.generic.InvokeDynamic.getReturnType(InvokeDynamic.java:99)
[ERROR] at org.aspectj.apache.bcel.generic.InvokeInstruction.produceStack(InvokeInstruction.java:107)
[ERROR] at org.aspectj.apache.bcel.generic.MethodGen.getMaxStack(MethodGen.java:988)
[ERROR] at org.aspectj.apache.bcel.generic.MethodGen.setMaxStack(MethodGen.java:876)
[ERROR] at org.aspectj.weaver.bcel.LazyMethodGen.pack(LazyMethodGen.java:1019)

The context is:
- Project uses lambda expressions.
- Java 1.8.11 on gentoo linux 64b.
- aspectjrt, aspectjtools 1.8.2
- aspectj-maven-plugin 1.7

[1] https://github.com/rydnr/LambdaControlFlowPoC
[2] https://github.com/rydnr/LambdaControlFlowPoC/blob/master/src/main/aspect/org/acmsl/pocs/lambdafor/ForReplacer.aj

I'm attaching the Maven project with a (hopefully) resolvable pom should it helps to figure out the issue. Just run mvn test.

I've downloaded aspectj 1.8.2 sources, and when debugging, the invalid cast is produced by extracting "org/acmsl/pocs/lambdafor/ControlFlowCommand" String from the constant pool at index 62.
I've no idea what could be causing this. I've tried adding some defensive programming hacks but it causes one NPE in the caller for each guarding condition. I think InvokeDynamic class is not prepared yet to handle ConstantUtf8 instances, but I'm far from solving this by myself.

Thank you very much in advance.

Jose.
Comment 1 Andrew Clement CLA 2014-09-29 16:17:29 EDT
Thanks for the test project, very useful.

I think I've distilled it to this:
===
import java.util.*;

public class Code {
  public void m() { }
}

aspect X {
  void around(): execution(* m(..)) {
    Arrays.asList(4, 5, 6).forEach((i) -> { System.out.println(i);});
  }
}
===

and it relates to the inlining of around advice (the constant pool isn't copied across properly for some reason).  If you turn off inlining, that may change what you see (-XnoInline on the command... not sure in maven)
Comment 2 Andrew Clement CLA 2014-09-30 12:43:27 EDT
Inlining around advice that contains invokedynamic is non trivial. Unlike the other instructions there is more to 'copy over' to the target including the bootstrap methods and the method in the aspect that represents the lambda expression.  It is not clear to me the lambda meta factory in the JDK will behave itself when the lambda expression method is copied over like this (I'm thinking about lambdas that capture 'this' for example). The quick solution is to mark advice that contains invokedynamic as not suitable for inlining.
Comment 3 Andrew Clement CLA 2014-09-30 14:09:59 EDT
I've committed my proposed changes. At least it shouldn't fail now but it will not be as optimal as inlining around advice. I will leave this bug open to cover doing the right thing when I have more time to craft a ton of tests.
Comment 4 Jose San Leandro CLA 2014-10-01 23:38:35 EDT
With -XnoInline (<XnoInline>true</XnoInline> in Maven's pom.xml) works.

Thanks Andy.
Comment 5 Andrew Clement CLA 2014-10-07 19:35:53 EDT
marking as fixed.