Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IllegalArgumentException: Cannot create Method for class initializer #1320

Closed
dmlloyd opened this issue May 22, 2019 · 14 comments

Comments

4 participants
@dmlloyd
Copy link
Contributor

commented May 22, 2019

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.

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

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?

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

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.

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

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.

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

I'll make this into a PR though, maybe it's not wrong.

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 22, 2019

Created #1321.

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 23, 2019

Ping @cstancu - this is a problem for Quarkus; is there any chance the PR could make it in to a 19 release?

@cstancu cstancu self-assigned this May 23, 2019

@christianwimmer

This comment has been minimized.

Copy link
Member

commented May 24, 2019

@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)?

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 24, 2019

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.

@christianwimmer

This comment has been minimized.

Copy link
Member

commented May 24, 2019

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.

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 24, 2019

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.

@christianwimmer

This comment has been minimized.

Copy link
Member

commented May 24, 2019

OK. We are going to fix this on the JVMCI level.

@christianwimmer

This comment has been minimized.

Copy link
Member

commented May 24, 2019

Fix is merged: graalvm/graal-jvmci-8@2749403

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.

@dmlloyd

This comment has been minimized.

Copy link
Contributor Author

commented May 25, 2019

Great, thanks.

@thomaswue

This comment has been minimized.

Copy link
Member

commented May 30, 2019

@dmlloyd We are backporting this for the 19.0.1 update. Are there any other blockers on your side we should prioritize?

@dmlloyd dmlloyd referenced this issue Jun 11, 2019

Closed

GraalVM 19.0 Blocker List #2792

4 of 5 tasks complete
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.