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

[native-image] Groovy static script - native-image-agent adds java.lang.reflect.Executable to reflect-config.json which breaks native image generation #1260

Closed
wololock opened this issue May 10, 2019 · 3 comments
Assignees

Comments

@wololock
Copy link

Environment:

  • GraalVM CE 19.0.0
  • Groovy 2.5.7

I'm testing some of my Groovy GraalVM examples, and I've found a weird issue I thought you might be interested in. I'm testing reflect-config.json file generation using native-image-agent. For a simple "Hello, World!" like Groovy application, it produces the following reflection configuration file. (It's 598 lines, so I'm pasting a Gist instead of the JSON file content.)

https://gist.github.com/wololock/47b8ff2fd9f3a4e0a3fff85e6fe32f89

The agent creates empty jni-config.json and proxy-config.json files. The resource-config.json file has the following content:

{
  "resources":[{"pattern":"META-INF/dgminfo"}]
}

When I try to create a native image using the following options:

native-image --allow-incomplete-classpath \
    -H:+AllowVMInspection \
    -H:+ReportUnsupportedElementsAtRuntime \
    -H:ConfigurationFileDirectories=out/conf/ \
    --initialize-at-build-time \
    --initialize-at-run-time=org.codehaus.groovy.control.XStreamUtils,groovy.grape.GrapeIvy \
    --no-fallback \
    --no-server \
    -cp ${CLASSPATH} \
    hello

It fails with the following error:

[hello:17248]    classlist:   2,554.40 ms
[hello:17248]        (cap):     815.35 ms
[hello:17248]        setup:   1,895.03 ms
[hello:17248]     analysis:  19,254.10 ms
Error: Field java.lang.reflect.Method.defaultValue is not present on type java.lang.reflect.Constructor. Error encountered while analysing java.lang.reflect.Method.getDefaultValue() 
Parsing context:
	parsing org.codehaus.groovy.vmplugin.v5.Java5.setMethodDefaultValue(Java5.java:355)
	parsing org.codehaus.groovy.vmplugin.v5.Java5.configureClassNode(Java5.java:379)
	parsing org.codehaus.groovy.ast.ClassNode.lazyClassInit(ClassNode.java:280)
	parsing org.codehaus.groovy.ast.ClassNode.getAnnotations(ClassNode.java:1456)
	parsing org.codehaus.groovy.transform.trait.Traits.collectSelfTypes(Traits.java:330)
	parsing org.codehaus.groovy.runtime.ProxyGeneratorAdapter.collectTraits(ProxyGeneratorAdapter.java:243)
	parsing org.codehaus.groovy.runtime.ProxyGeneratorAdapter.adjustSuperClass(ProxyGeneratorAdapter.java:210)
	parsing org.codehaus.groovy.runtime.ProxyGeneratorAdapter.<init>(ProxyGeneratorAdapter.java:160)
	parsing groovy.util.ProxyGenerator.createAdapter(ProxyGenerator.java:230)
	parsing groovy.util.ProxyGenerator.instantiateAggregate(ProxyGenerator.java:167)
	parsing groovy.util.ProxyGenerator.instantiateAggregate(ProxyGenerator.java:158)
	parsing groovy.util.ProxyGenerator.instantiateAggregate(ProxyGenerator.java:154)
	parsing org.codehaus.groovy.reflection.stdclasses.CachedSAMClass.coerceToSAM(CachedSAMClass.java:80)
	parsing org.codehaus.groovy.reflection.stdclasses.CachedSAMClass.coerceToSAM(CachedSAMClass.java:65)
	parsing org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.continueCastOnSAM(DefaultTypeTransformation.java:364)
	parsing org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.continueCastOnNumber(DefaultTypeTransformation.java:329)
	parsing org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.castToType(DefaultTypeTransformation.java:243)
	parsing org.codehaus.groovy.reflection.ParameterTypes.makeCommonArray(ParameterTypes.java:235)
	parsing org.codehaus.groovy.reflection.ParameterTypes.fitToVargs(ParameterTypes.java:223)
	parsing org.codehaus.groovy.reflection.ParameterTypes.correctArguments(ParameterTypes.java:173)
	parsing org.codehaus.groovy.reflection.ParameterTypes.coerceArgumentsToClasses(ParameterTypes.java:145)
	parsing groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:321)
	parsing groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1217)
	parsing groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1041)
	parsing org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:1011)
	parsing org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:994)
	parsing org.codehaus.groovy.runtime.InvokerHelper.runScript(InvokerHelper.java:423)
	parsing hello.main(hello.groovy)
	parsing com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:153)
	parsing com.oracle.svm.core.code.IsolateEnterStub.JavaMainWrapper_run_5087f5482cc9a6abc971913ece43acb471d2631b(generated:0)

Error: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
Error: Image build request failed with exit status 1

I tracked down the problem and it turns out that this exception occurs only when reflect-config.json file contains reflection configuration for java.lang.reflect.Executable class.

{
  "name":"java.lang.reflect.Executable",
  "allDeclaredMethods":true,
  "methods":[
    {"name":"getAnnotation","parameterTypes":["java.lang.Class"] }, 
    {"name":"getDeclaredAnnotations","parameterTypes":[] }, 
    {"name":"getDeclaringClass","parameterTypes":[] }, 
    {"name":"getModifiers","parameterTypes":[] }, 
    {"name":"getName","parameterTypes":[] }, 
    {"name":"getTypeParameters","parameterTypes":[] }, 
    {"name":"isSynthetic","parameterTypes":[] }
  ]
},

If I only remove this single entry from the reflect-config.json file, the native image generation succeeds and the "Hello, World!" program compiles and executes without any issue.

I wonder if it is correct that the java.lang.reflect.Executable class gets discovered and added to the reflection configuration file in this case. Is there an option for the agent that allows to filter out specific classes from adding them to the reflection configuration class?

All source codes from my "Hello, World!" Groovy example can be found here - https://github.com/wololock/graalvm-groovy-examples/tree/master/hello-world I "improved" compile.sh script file so right before running native-image command it rewrites reflect-config.json file and it removes java.lang.reflect.Executable entry from the list. You can turn it off by commenting out the following line in the compile.sh script - https://github.com/wololock/graalvm-groovy-examples/blob/master/hello-world/compile.sh#L26

@cstancu
Copy link
Member

cstancu commented May 10, 2019

The Error: Field java.lang.reflect.Method.defaultValue is not present on type java.lang.reflect.Constructor issue was fixed by 1873d37 which didn't make it in the release. However, having a filtering mechanism for the generated reflection configuration would be useful.

@peter-hofer
Copy link
Member

As @cstancu says, broken reflective access to java.lang.reflect.Method is a bug that unfortunately wasn't fixed in time for the release.
Registering reflection classes themselves for reflective usage is a perfectly valid use case however. I ran your code and looked at the trace file and it is the Groovy class org.codehaus.groovy.reflection.stdclasses.CachedSAMClass that reflectively uses java.lang.reflect.Executable.

@wololock
Copy link
Author

@cstancu @peter-hofer Thanks for the details! Waiting for the upcoming update then 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants