JDK-8327499 : MethodHandleStatics.traceLambdaForm includes methods that cannot be generated
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang.invoke
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2024-03-06
  • Updated: 2024-07-11
  • Resolved: 2024-05-13
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 23
23 b23Fixed
Related Reports
Relates :  
Description
The following bug can be reproduced with this commit
https://github.com/openjdk/jdk/commit/989fc3e6ea65e530055296ac4bc181cb5c6a41ea

[1] Apply the following patch for diagnosis. Build a non-product JVM:

diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp
index 500036febab..39850d1d208 100644
--- a/src/hotspot/share/prims/jvm.cpp
+++ b/src/hotspot/share/prims/jvm.cpp
@@ -3715,6 +3715,8 @@ JVM_ENTRY_NO_ENV(jint, JVM_GetCDSConfigStatus())
   return CDSConfig::get_status();
 JVM_END
 
+extern "C" JNIEXPORT void ps();
+
 JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line))
 #if INCLUDE_CDS
   assert(CDSConfig::is_logging_lambda_form_invokers(), "sanity");
@@ -3730,6 +3732,11 @@ JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line))
     if (ClassListWriter::is_enabled()) {
       ClassListWriter w;
       w.stream()->print_cr("%s %s", LAMBDA_FORM_TAG, c_line);
+      if (strstr(c_line, "L3I_L") != nullptr &&
+          strstr(c_line, "Invokers$Holder") != nullptr) {
+        tty->print_cr("%s", c_line);
+        ps();
+      }
     }
   }

[2] Create this file: TestInvokers.java

=================
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;

public class TestInvokers {
    public static void main(String args[]) throws Exception {
        MethodType type = MethodType.methodType(Object.class, Object.class, int.class);
        System.out.println(type);
        MethodHandle inv = MethodHandles.invoker(type);
        System.out.println(inv);
    }
}
=================

[3] Run the following commands:

$ javac TestInvokers.java
$ java -XX:DumpLoadedClassList=TestInvokers.classlist -cp . TestInvokers

(Object,int)Object
[LF_RESOLVE] java.lang.invoke.Invokers$Holder invoker L3I_L

"Executing ps"
 for thread: "main" #1 [1018846] prio=5 os_prio=0 cpu=265.15ms elapsed=0.27s tid=0x00007fe2d002a150 nid=1018846 runnable  [0x00007fe2d6047000]
   java.lang.Thread.State: RUNNABLE
Thread: 0x00007fe2d002a150  [0xf8bde] State: _running _at_poll_safepoint 0
   JavaThread state: _thread_in_vm

	at jdk.internal.misc.CDS.logLambdaFormInvoker(java.base@23-internal/Native Method)
	at jdk.internal.misc.CDS.logLambdaFormInvoker(java.base@23-internal/CDS.java:110)
	at java.lang.invoke.MethodHandleStatics.traceLambdaForm(java.base@23-internal/MethodHandleStatics.java:138)
	at java.lang.invoke.InvokerBytecodeGenerator.resolveFrom(java.base@23-internal/InvokerBytecodeGenerator.java:648)
	at java.lang.invoke.InvokerBytecodeGenerator.lookupPregenerated(java.base@23-internal/InvokerBytecodeGenerator.java:674)
	at java.lang.invoke.InvokerBytecodeGenerator.generateCustomizedCode(java.base@23-internal/InvokerBytecodeGenerator.java:708)
	at java.lang.invoke.LambdaForm.compileToBytecode(java.base@23-internal/LambdaForm.java:849)
	at java.lang.invoke.LambdaForm.prepare(java.base@23-internal/LambdaForm.java:807)
	at java.lang.invoke.MethodHandle.<init>(java.base@23-internal/MethodHandle.java:482)
	at java.lang.invoke.BoundMethodHandle.<init>(java.base@23-internal/BoundMethodHandle.java:52)
	at java.lang.invoke.BoundMethodHandle$Species_L.<init>(java.base@23-internal/BoundMethodHandle.java:210)
	at java.lang.invoke.BoundMethodHandle$Species_L.make(java.base@23-internal/BoundMethodHandle.java:225)
	at java.lang.invoke.BoundMethodHandle.bindSingle(java.base@23-internal/BoundMethodHandle.java:66)
	at java.lang.invoke.Invokers.makeExactOrGeneralInvoker(java.base@23-internal/Invokers.java:147)
	at java.lang.invoke.Invokers.genericInvoker(java.base@23-internal/Invokers.java:80)
	at java.lang.invoke.MethodHandles.invoker(java.base@23-internal/MethodHandles.java:4771)
	at TestInvokers.main(TestInvokers.java:9)
MethodHandle(MethodHandle,Object,int)Object

$ grep Invokers.Holder.*L3I_L lst
@lambda-form-invoker [LF_RESOLVE] java.lang.invoke.Invokers$Holder invoker L3I_L

$ d -Xshare:dump -XX:SharedArchiveFile=jsa -XX:SharedClassListFile=lst
[0.752s][error][cds] java.lang.RuntimeException: Invoker type parameter must start and end with Object: L3I_L
[0.752s][error][cds] Failed to generate LambdaForm holder classes. Is your classlist out of date?

==================================
Note that MethodHandleStatics.traceLambdaForm produces the trace

[LF_RESOLVE] java.lang.invoke.Invokers$Holder invoker L3I_L

However, this invoker cannot be generated due to this check:

https://github.com/openjdk/jdk/blob/989fc3e6ea65e530055296ac4bc181cb5c6a41ea/src/java.base/share/classes/java/lang/invoke/GenerateJLIClassesHelper.java#L139-L141

if (mt.parameterCount() < 2 ||
    mt.parameterType(0) != Object.class ||
    mt.parameterType(lastParam) != Object.class) {
    throw new RuntimeException(
       "Invoker type parameter must start and end with Object: " + invokerType);
}


Comments
A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/19164 Date: 2024-05-10 00:45:31 +0000
11-07-2024

Changeset: adaa509b Author: Chen Liang <liach@openjdk.org> Committer: Claes Redestad <redestad@openjdk.org> Date: 2024-05-13 09:11:49 +0000 URL: https://git.openjdk.org/jdk/commit/adaa509b6ed3d12569b8e5f2ec802cef22ab53c7
13-05-2024

GenerateJLIClassesHelper is buggy here: it avoids generating INVOKER without trailing reference type (MethodType), but only LINKER ever require trailing reference type: https://github.com/openjdk/jdk/blob/989fc3e6ea65e530055296ac4bc181cb5c6a41ea/src/java.base/share/classes/java/lang/invoke/Invokers.java#L311 Since Invoker and Linkers are different, I propose track them separately for generation; they are already distinct in logging.
09-05-2024

The exceptions in GenerateJLIClassesHelper were added by JDK-8252725. I think the intention is to catch user errors in the classlist file -- if the user edits the classfile manually, an unsupported invoker type may be added inadvertently. However, these exceptions also caught problems in the JDK itself, because MethodHandleStatics.traceLambdaForm could generate invalid input for GenerateJLIClassesHelper. Potentially, this could cause the JDK build to fail if GenerateJLIClassesPlugin is used with a training run that causes such invalid lines to be generated.
06-03-2024