JDK-8277964 : ClassCastException with no stack trace is thrown with -Xcomp in method handle invocation
  • Type: Bug
  • Component: hotspot
  • Sub-Component: compiler
  • Affected Version: 18
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2021-11-30
  • Updated: 2022-01-03
  • Resolved: 2021-12-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 18 JDK 19
18 b29Fixed 19Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
Constructor0204 test expects IllegalArgumentException thrown due to wrong parameter type, something like this:

  Class params[] = {int.class};
  Constructor c = T.class.getConstructor( params );
  Object args[] = {int.class};
  T ob = (T) (c.newInstance( args ));

But VM throws ClassCastException with no stack trace during the invocation of a method handle when running with -Xcomp in the new core reflection implementation after JEP 416 is integrated.   InvocationTargetException wrapping CCE is thrown instead. 

Constructor0204: Failed. Constructor0204: unexpected java.lang.reflect.InvocationTargetException thrown

java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:72)
	at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:483)
	at javasoft.sqe.tests.api.java.lang.reflect.Constructor.CNewInstanceTests.Constructor0204(CNewInstanceTests.java:167)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:577)
	at javasoft.sqe.javatest.lib.MultiTest.invokeTestCase(MultiTest.java:406)
	at javasoft.sqe.javatest.lib.MultiTest.run(MultiTest.java:195)
	at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
	at java.base/java.lang.reflect.Method.invoke(Method.java:577)
	at com.sun.jck.lib.ExecJCKTestSameJVMCmd$Version2Test.execute(ExecJCKTestSameJVMCmd.java:603)
	at com.sun.jck.lib.ExecJCKTestSameJVMCmd$StandardTest.run(ExecJCKTestSameJVMCmd.java:560)
	at com.sun.jck.lib.ExecJCKTestSameJVMCmd.execute(ExecJCKTestSameJVMCmd.java:444)
	at com.sun.jck.lib.ExecJCKTestSameJVMCmd.run(ExecJCKTestSameJVMCmd.java:374)
	at com.sun.jck.lib.ExecInSeparateThreadCmd$StatusCallable.call(ExecInSeparateThreadCmd.java:76)
	at com.sun.jck.lib.ExecInSeparateThreadCmd$StatusCallable.call(ExecInSeparateThreadCmd.java:60)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: java.lang.ClassCastException
Comments
Changeset: d3408a46 Author: Vladimir Kozlov <kvn@openjdk.org> Date: 2021-12-15 21:45:45 +0000 URL: https://git.openjdk.java.net/jdk18/commit/d3408a46b7c8c2f8b5e41f3e286a497064a2c104
15-12-2021

https://github.com/openjdk/jdk18/pull/27
15-12-2021

A proper fix for this is to use the catchException combination. However, that introduces significant cold startup performance regression. JDK-8278447 tracks the work to address the performance regression using catchException and asSpreader combinator. It may require significant work and refactoring which is risky for JDK 18. It is proposed to implement a workaround to white list the relevant methods (all methods in sun.invoke.util.ValueConversions class) not to omit stack trace when exception is thrown.
15-12-2021

Thanks Vladimir. This patch does workaround the issue. I'll measure the performance impact to normal application.
14-12-2021

[~mchung] I attached HotSpot patch with changes you asked. Please, try it. It is based on latest JDK (19).
14-12-2021

[~alanb] We can do it as temporary workaround. We have only one place in C2 which checks this flag so we can relax the check for particular method or class. Which one method/class do you have in mind?
08-12-2021

[~thartmann] thanks for the investigation. The choice to decode the stack trace from the exception thrown instead of using catchException combinator is due to the cold startup regression. The proper solution for this is to look into a performant way to use catchException to replace the stack trace decoding logic.
30-11-2021

Moving to core-libs/java.lang:reflect
30-11-2021

This is not a compiler bug but an issue in AccessorUtils::isIllegalArgument which inspects the stack trace of an exception. With C2's OmitStackTraceInFastThrow optimization, the stack trace is omitted for exceptions that are often thrown, for performance reasons. This leads to isIllegalArgument returning an incorrect result to DirectConstructorHandleAccessor::newInstance which then throws an InvocationTargetException instead of an IllegalArgumentException. To verify, C2's optimization can be turned off via -XX:-OmitStackTraceInFastThrow.
30-11-2021

ILW = Incorrect execution of C2 compiled code (wrong exception thrown), single JCK test, no known workaround = HLH = P2
30-11-2021