Details
-
Bug
-
Resolution: Fixed
-
P2
-
21
-
b22
-
Verified
Description
As a result of the changes for JDK-8301995, `HotSpotConstantPool#lookupBootstrapMethodIntrospection` is broken as it no longer decodes the correct constant pool index for looking up the bootstrap method invocation for invokedynamic.
This breaks native image on JDK 21+16, resulting in all kind of follow-up exception, for example:
```
Caused by: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "o" is null
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.checkReceiver(DirectMethodHandleAccessor.java:196)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:99)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.infrastructure.WrappedConstantPool$WrappedBootstrapMethodInvocation.getMethod(WrappedConstantPool.java:210)
```
The problem can easily be observed using the following patch for `TestDynamicConstant.java`:
```
diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
index 6f94877b9..014154978 100644
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
@@ -333,6 +333,8 @@ private static void testLoadReferencedType(ResolvedJavaMethod method) {
Assert.assertTrue((code[bci] & 0xff) == INVOKEDYNAMIC, "unexpected bytecode");
int cpi = beS4(code, bci + 1);
method.getConstantPool().loadReferencedType(cpi, INVOKEDYNAMIC, false);
+ BootstrapMethodInvocation bmi = method.getConstantPool().lookupBootstrapMethodInvocation(cpi, INVOKEDYNAMIC);
+ Assert.assertEquals(bmi.getName(), "do_concat");
}
// @formatter:off
```
This results in an IOOB exception because a nonsense constant pool index is returned:
```
test jdk.vm.ci.hotspot.test.TestDynamicConstant.test(): failure
java.lang.IndexOutOfBoundsException: index 0 not between 1 and 35
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotConstantPool.checkBounds(HotSpotConstantPool.java:490)
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotConstantPool.getTagAt(HotSpotConstantPool.java:316)
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotConstantPool.lookupBootstrapMethodInvocation(HotSpotConstantPool.java:596)
at jdk.vm.ci.hotspot.test.TestDynamicConstant.testLoadReferencedType(TestDynamicConstant.java:336)
at jdk.vm.ci.hotspot.test.TestDynamicConstant.testLookupBootstrapMethodInvocation(TestDynamicConstant.java:320)
at jdk.vm.ci.hotspot.test.TestDynamicConstant.test(TestDynamicConstant.java:285)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:132)
at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:599)
at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:174)
at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:822)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:147)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.testng.TestRunner.privateRun(TestRunner.java:764)
at org.testng.TestRunner.run(TestRunner.java:585)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1218)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
at org.testng.TestNG.runSuites(TestNG.java:1069)
at org.testng.TestNG.run(TestNG.java:1037)
at com.sun.javatest.regtest.agent.TestNGRunner.main(TestNGRunner.java:102)
at com.sun.javatest.regtest.agent.TestNGRunner.main(TestNGRunner.java:58)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at com.sun.javatest.regtest.agent.MainWrapper$MainTask.run(MainWrapper.java:138)
at java.base/java.lang.Thread.run(Thread.java:1592)
```
This breaks native image on JDK 21+16, resulting in all kind of follow-up exception, for example:
```
Caused by: java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "o" is null
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.checkReceiver(DirectMethodHandleAccessor.java:196)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:99)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at org.graalvm.nativeimage.pointsto/com.oracle.graal.pointsto.infrastructure.WrappedConstantPool$WrappedBootstrapMethodInvocation.getMethod(WrappedConstantPool.java:210)
```
The problem can easily be observed using the following patch for `TestDynamicConstant.java`:
```
diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
index 6f94877b9..014154978 100644
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestDynamicConstant.java
@@ -333,6 +333,8 @@ private static void testLoadReferencedType(ResolvedJavaMethod method) {
Assert.assertTrue((code[bci] & 0xff) == INVOKEDYNAMIC, "unexpected bytecode");
int cpi = beS4(code, bci + 1);
method.getConstantPool().loadReferencedType(cpi, INVOKEDYNAMIC, false);
+ BootstrapMethodInvocation bmi = method.getConstantPool().lookupBootstrapMethodInvocation(cpi, INVOKEDYNAMIC);
+ Assert.assertEquals(bmi.getName(), "do_concat");
}
// @formatter:off
```
This results in an IOOB exception because a nonsense constant pool index is returned:
```
test jdk.vm.ci.hotspot.test.TestDynamicConstant.test(): failure
java.lang.IndexOutOfBoundsException: index 0 not between 1 and 35
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotConstantPool.checkBounds(HotSpotConstantPool.java:490)
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotConstantPool.getTagAt(HotSpotConstantPool.java:316)
at jdk.internal.vm.ci/jdk.vm.ci.hotspot.HotSpotConstantPool.lookupBootstrapMethodInvocation(HotSpotConstantPool.java:596)
at jdk.vm.ci.hotspot.test.TestDynamicConstant.testLoadReferencedType(TestDynamicConstant.java:336)
at jdk.vm.ci.hotspot.test.TestDynamicConstant.testLookupBootstrapMethodInvocation(TestDynamicConstant.java:320)
at jdk.vm.ci.hotspot.test.TestDynamicConstant.test(TestDynamicConstant.java:285)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:132)
at org.testng.internal.TestInvoker.invokeMethod(TestInvoker.java:599)
at org.testng.internal.TestInvoker.invokeTestMethod(TestInvoker.java:174)
at org.testng.internal.MethodRunner.runInSequence(MethodRunner.java:46)
at org.testng.internal.TestInvoker$MethodInvocationAgent.invoke(TestInvoker.java:822)
at org.testng.internal.TestInvoker.invokeTestMethods(TestInvoker.java:147)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:146)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:128)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at org.testng.TestRunner.privateRun(TestRunner.java:764)
at org.testng.TestRunner.run(TestRunner.java:585)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:384)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:378)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:337)
at org.testng.SuiteRunner.run(SuiteRunner.java:286)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:53)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:96)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1218)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1140)
at org.testng.TestNG.runSuites(TestNG.java:1069)
at org.testng.TestNG.run(TestNG.java:1037)
at com.sun.javatest.regtest.agent.TestNGRunner.main(TestNGRunner.java:102)
at com.sun.javatest.regtest.agent.TestNGRunner.main(TestNGRunner.java:58)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at com.sun.javatest.regtest.agent.MainWrapper$MainTask.run(MainWrapper.java:138)
at java.base/java.lang.Thread.run(Thread.java:1592)
```
Attachments
Issue Links
- relates to
-
JDK-8301995 Move invokedynamic resolution information out of ConstantPoolCacheEntry
- Resolved