Here's the error:
Fatal error: java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Cannot create java.lang.reflect.Method for class initializer
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
at java.util.concurrent.ForkJoinTask.get(ForkJoinTask.java:1005)
at com.oracle.svm.hosted.NativeImageGenerator.run(NativeImageGenerator.java:458)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.buildImage(NativeImageGeneratorRunner.java:289)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.build(NativeImageGeneratorRunner.java:427)
at com.oracle.svm.hosted.NativeImageGeneratorRunner.main(NativeImageGeneratorRunner.java:109)
Caused by: java.lang.IllegalArgumentException: Cannot create java.lang.reflect.Method for class initializer
at jdk.vm.ci.hotspot.CompilerToVM.asReflectionExecutable(Native Method)
at jdk.vm.ci.hotspot.HotSpotJDKReflection.getMethod(HotSpotJDKReflection.java:446)
at jdk.vm.ci.hotspot.HotSpotJDKReflection.getMethodAnnotation(HotSpotJDKReflection.java:175)
at jdk.vm.ci.hotspot.HotSpotResolvedJavaMethodImpl.getAnnotation(HotSpotResolvedJavaMethodImpl.java:540)
at org.graalvm.util.GuardedAnnotationAccess.getAnnotation(GuardedAnnotationAccess.java:52)
at org.graalvm.util.GuardedAnnotationAccess.isAnnotationPresent(GuardedAnnotationAccess.java:47)
at com.oracle.svm.hosted.cenum.CEnumCallWrapperSubstitutionProcessor.lookup(CEnumCallWrapperSubstitutionProcessor.java:54)
at com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor$ChainedSubstitutionProcessor.lookup(SubstitutionProcessor.java:128)
at com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor$ChainedSubstitutionProcessor.lookup(SubstitutionProcessor.java:128)
at com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor$ChainedSubstitutionProcessor.lookup(SubstitutionProcessor.java:128)
at com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor$ChainedSubstitutionProcessor.lookup(SubstitutionProcessor.java:128)
at com.oracle.graal.pointsto.infrastructure.SubstitutionProcessor$ChainedSubstitutionProcessor.lookup(SubstitutionProcessor.java:128)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookupAllowUnresolved(AnalysisUniverse.java:396)
at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookup(AnalysisUniverse.java:376)
at com.oracle.graal.pointsto.meta.AnalysisType.getClassInitializer(AnalysisType.java:962)
at com.oracle.svm.hosted.classinitialization.TypeInitializerGraph.shouldPromoteToUnsafe(TypeInitializerGraph.java:196)
at com.oracle.svm.hosted.classinitialization.TypeInitializerGraph.lambda$updateTypeInitializerSafety$3(TypeInitializerGraph.java:134)
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:174)
at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1556)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.oracle.svm.hosted.classinitialization.TypeInitializerGraph.updateTypeInitializerSafety(TypeInitializerGraph.java:134)
at com.oracle.svm.hosted.classinitialization.TypeInitializerGraph.computeInitializerSafety(TypeInitializerGraph.java:113)
at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.beforeCompilation(ClassInitializationFeature.java:215)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$doRun$2(NativeImageGenerator.java:572)
at com.oracle.svm.hosted.FeatureHandler.forEachFeature(FeatureHandler.java:64)
at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:572)
at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:441)
at java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1386)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Error: Image build request failed with exit status 1
To dig into this I attached a debugger. It looks like we're getting to here (com/oracle/graal/pointsto/meta/AnalysisType.java:964):
@Override
public AnalysisMethod getClassInitializer() {
return universe.lookup(wrapped.getClassInitializer());
}
The wrapped.getClassInitializer() is returning a method whose toString is HotSpotMethod<HttpRequestParser$$generated.<clinit>()>, which seems to make sense. Later in the stack the recursive lookups arrive at com.oracle.svm.hosted.cenum.CEnumCallWrapperSubstitutionProcessor#lookup which tries to find annotations on the method, but the method is <clinit> so presumably that's not going to work out well.
Adding this patch seems to make no difference:
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
index b39351e464f..777a139e53f 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
@@ -51,8 +51,8 @@ public class CEnumCallWrapperSubstitutionProcessor extends SubstitutionProcessor
@Override
public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
- if (GuardedAnnotationAccess.isAnnotationPresent(method, CEnumLookup.class) ||
- GuardedAnnotationAccess.isAnnotationPresent(method, CEnumValue.class)) {
+ if (! method.getName().contains("<clinit>") && (GuardedAnnotationAccess.isAnnotationPresent(method, CEnumLookup.class) ||
+ GuardedAnnotationAccess.isAnnotationPresent(method, CEnumValue.class))) {
return callWrappers.computeIfAbsent(method, v -> new CEnumCallWrapperMethod(nativeLibraries, v));
} else {
return method;
Whether or not it's correct, I don't know. Maybe we're registering some reflection class wrongly?
I also tried this (which didn't work):
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
index b39351e464f..7423644ef5c 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
@@ -51,8 +51,8 @@ public class CEnumCallWrapperSubstitutionProcessor extends SubstitutionProcessor
@Override
public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
- if (GuardedAnnotationAccess.isAnnotationPresent(method, CEnumLookup.class) ||
- GuardedAnnotationAccess.isAnnotationPresent(method, CEnumValue.class)) {
+ if (! method.isClassInitializer() && (GuardedAnnotationAccess.isAnnotationPresent(method, CEnumLookup.class) ||
+ GuardedAnnotationAccess.isAnnotationPresent(method, CEnumValue.class))) {
return callWrappers.computeIfAbsent(method, v -> new CEnumCallWrapperMethod(nativeLibraries, v));
} else {
return method;
I'll have to do some more debugging to see what it's trying to do.
OK looks like there are two spots that need patching:
diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java
index 445fb7225a1..d0707e0867e 100644
--- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java
+++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisUniverse.java
@@ -401,7 +401,7 @@ public class AnalysisUniverse implements Universe {
}
private AnalysisMethod createMethod(ResolvedJavaMethod method) {
- if (!platformSupported(method)) {
+ if (!method.isClassInitializer() && !platformSupported(method)) {
throw new UnsupportedFeatureException("Method " + method.format("%H.%n(%p)" + " is not available in this platform."));
}
if (sealed) {
diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
index b39351e464f..eb3382c55b7 100644
--- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
+++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/cenum/CEnumCallWrapperSubstitutionProcessor.java
@@ -51,8 +51,8 @@ public class CEnumCallWrapperSubstitutionProcessor extends SubstitutionProcessor
@Override
public ResolvedJavaMethod lookup(ResolvedJavaMethod method) {
- if (GuardedAnnotationAccess.isAnnotationPresent(method, CEnumLookup.class) ||
- GuardedAnnotationAccess.isAnnotationPresent(method, CEnumValue.class)) {
+ if (!method.isClassInitializer() && (GuardedAnnotationAccess.isAnnotationPresent(method, CEnumLookup.class) ||
+ GuardedAnnotationAccess.isAnnotationPresent(method, CEnumValue.class))) {
return callWrappers.computeIfAbsent(method, v -> new CEnumCallWrapperMethod(nativeLibraries, v));
} else {
return method;
Maybe this is due to a JVMCI update or something? But with these two patches I don't get the error anymore.
I'll make this into a PR though, maybe it's not wrong.
Created #1321.
Ping @cstancu - this is a problem for Quarkus; is there any chance the PR could make it in to a 19 release?
@dmlloyd Can you share some more details about this class initializer: HttpRequestParser$$generated.<clinit>().
Is this a class initializer that has an annotation? I don't think that is even possible to do in regular Java code. And in manually crafted bytecode, why would you put an annotation on it when there is no way to ever access this annotation (since you cannot get a java.lang.reflect.Method object for a class initializer)?
It is crafted bytecode, but it is not annotated as far as I can tell (tooling might be hiding something though; I'll have to dig into the raw bytes to be certain). My impression was that the exception occurs simply when asked to look for annotations on a class initializer though.
The output of javap makes it seem like maybe the attributes are present even if there are no annotations in them:
public static {} throws ;
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Exceptions:
throws
Code:
stack=3, locals=2, args_size=0
0: invokestatic #21 // Method io/undertow/server/protocol/http/HttpRequestParser.httpStrings:()Ljava/util/Map;
3: astore_1
4: ldc #27 // String OPTIONS
6: ldc #31 // String ISO-8859-1
8: invokevirtual #35 // Method java/lang/String.getBytes:(Ljava/lang/String;)[B
11: putstatic #38 // Field STATE_BYTES_3:[B
[...]
18222: pop
18223: new #48 // class io/undertow/util/HttpString
18226: dup
18227: ldc_w #2554 // String Warning
18230: invokespecial #53 // Method io/undertow/util/HttpString."<init>":(Ljava/lang/String;)V
18233: putstatic #2595 // Field HTTP_STRING_756:Lio/undertow/util/HttpString;
18236: return
RuntimeVisibleAnnotations:
RuntimeVisibleParameterAnnotations:
Whether or not that makes a difference, I do not know. It didn't before today at any rate.
The JVMCI code has the following check before going to the java.lang.reflect.Method:
if ((getConstMethodFlags() & config().constMethodHasMethodAnnotations) == 0) {
return null;
}
For all class initializers that we have seen so far, that check was sufficient.
The JVM specification doesn't seem to forbid it, and it has worked for many years against every major JVM, so I'd still be inclined to say it's a bug, though whether it's a JVMCI bug or a GraalVM bug I don't know.
OK. We are going to fix this on the JVMCI level.
Fix is merged: https://github.com/graalvm/graal-jvmci-8/commit/274940343d45c77a722cbeaeda6529e9a254662a
Will be a bit though before we make the next release of a JVMCI JDK. The plan is also to backport to the 19 release branch.
Great, thanks.
@dmlloyd We are backporting this for the 19.0.1 update. Are there any other blockers on your side we should prioritize?