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

[GR-24133] JNI error while building SWT native image on MacOS #2232

Open
mbarbeaux opened this issue Mar 6, 2020 · 8 comments
Open

[GR-24133] JNI error while building SWT native image on MacOS #2232

mbarbeaux opened this issue Mar 6, 2020 · 8 comments
Assignees

Comments

@mbarbeaux
Copy link

Describe GraalVM and your environment :

  • GraalVM version or commit id if built from source: 20.0.0
  • CE or EE: CE
  • Build Time or run time failure: build time
  • JDK version: JDK8
  • Native compiler information:
    Run the following to capture compiler version
    • In windows: cl.exe
    • In macOS : cc -v
    • In Linux: gcc --version
Apple clang version 11.0.0 (clang-1100.0.33.17)
Target: x86_64-apple-darwin19.3.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
  • Native linker information:
    Run the following to capture linker version
    • In windows: cl.exe
    • In macOS : cc -Wl,-v
    • In Linux: gcc -Wl,--version
@(#)PROGRAM:ld  PROJECT:ld64-530
BUILD 18:57:17 Dec 13 2019
configured to support archs: armv6 armv7 armv7s arm64 arm64e arm64_32 i386 x86_64 x86_64h armv6m armv7k armv7m armv7em
Library search paths:
	/usr/local/lib
	/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib
Framework search paths:
	/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks/
  • OS and OS Version: macOS Catalina 10.15.3
  • Architecture: amd64
  • The output of java -Xinternalversion:
OpenJDK 64-Bit Server VM GraalVM CE 20.0.0 (25.242-b06-jvmci-20.0-b02) for bsd-amd64 JRE (8u242), built on Jan 20 2020 12:54:03 by "graal" with gcc 4.2.1 Compatible Apple LLVM 8.1.0 (clang-802.0.42)

Have you verified this issue still happens when using the latest snapshot?
No

Describe the issue
Try to build a simple Hello World SWT application works both on Linux and Windows 10 with GraalVM 20.0.0 java8 CE, but not on Mac OS. Despite running the agent to generate JNI and other configuration files, it fails at build image time with an error :

atal error: com.oracle.graal.pointsto.util.AnalysisError$ParsingError: Error encountered while parsing org.eclipse.swt.widgets.Display.windowProc(long, long, long, long, long, long)
Parsing context:
	parsing com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_VARARGS:Lorg_eclipse_swt_widgets_Display_2_0002ewindowProc_00028JJJJJJ_00029J(generated:0)

	at com.oracle.graal.pointsto.util.AnalysisError.parsingError(AnalysisError.java:138)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:323)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureParsed(MethodTypeFlow.java:300)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:107)
	at com.oracle.graal.pointsto.flow.StaticInvokeTypeFlow.update(InvokeTypeFlow.java:346)
	at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:511)
	at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:171)
	at java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1402)
	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)
Caused by: org.graalvm.compiler.java.BytecodeParser$BytecodeParserError: org.graalvm.compiler.debug.GraalError: java.lang.reflect.InvocationTargetException
	at parsing org.eclipse.swt.widgets.Display.windowProc(Display.java:6681)
	at org.graalvm.compiler.java.BytecodeParser.throwParserError(BytecodeParser.java:2582)
	at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.throwParserError(SharedGraphBuilderPhase.java:94)
	at org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3402)
	at org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:3204)
	at org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:1085)
	at org.graalvm.compiler.java.BytecodeParser.buildRootMethod(BytecodeParser.java:979)
	at org.graalvm.compiler.java.GraphBuilderPhase$Instance.run(GraphBuilderPhase.java:84)
	at org.graalvm.compiler.phases.Phase.run(Phase.java:49)
	at org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:197)
	at org.graalvm.compiler.phases.Phase.apply(Phase.java:42)
	at org.graalvm.compiler.phases.Phase.apply(Phase.java:38)
	at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:221)
	at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:340)
	at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:310)
	... 10 more
Caused by: org.graalvm.compiler.debug.GraalError: java.lang.reflect.InvocationTargetException
	at org.graalvm.compiler.debug.GraalError.shouldNotReachHere(GraalError.java:55)
	at com.oracle.graal.pointsto.meta.AnalysisMethod.<init>(AnalysisMethod.java:149)
	at com.oracle.graal.pointsto.meta.AnalysisUniverse.createMethod(AnalysisUniverse.java:412)
	at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookupAllowUnresolved(AnalysisUniverse.java:400)
	at com.oracle.graal.pointsto.infrastructure.WrappedConstantPool.lookupMethod(WrappedConstantPool.java:116)
	at org.graalvm.compiler.java.BytecodeParser.lookupMethodInPool(BytecodeParser.java:4285)
	at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.lookupMethodInPool(SharedGraphBuilderPhase.java:107)
	at org.graalvm.compiler.java.BytecodeParser.lookupMethod(BytecodeParser.java:4279)
	at org.graalvm.compiler.java.BytecodeParser.genInvokeStatic(BytecodeParser.java:1656)
	at org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:5288)
	at org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3397)
	... 21 more
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.GeneratedMethodAccessor4.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.oracle.graal.pointsto.meta.AnalysisMethod.<init>(AnalysisMethod.java:147)
	... 30 more
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.eclipse.swt.internal.cocoa.Selector
	at org.eclipse.swt.widgets.Display.$SWITCH_TABLE$org$eclipse$swt$internal$cocoa$Selector(Display.java:104)
	... 34 more

Describe the full native-image command

Capture full native-image command by running with the `--verbose` flag e.g.:
 native-image --verbose [... other args]
native-image -cp target/graalvm-swt-native-image-1.0-SNAPSHOT.jar -H:Class=com.github.mbarbeaux.HelloSW -H:+ReportExceptionStackTraces -H:+TraceClassInitialization -H:+AllowVMInspection -H:+JNI --allow-incomplete-classpath --verbose --no-server --no-fallback --report-unsupported-elements-at-runtime -DremoveUnusedAutoconfig=true

Code snippet or code repository that reproduces the issue

https://github.com/mbarbeaux/graalvm-swt-native-image

Steps to reproduce the issue
Please include both build steps as well as run steps

  1. git clone https://github.com/mbarbeaux/graalvm-swt-native-image
  2. ./mvnw -Pagent clean package to generate/update configuration files with GraalVM agent
  3. ./mvnw -Pnative clean package to launch the native image building

Expected behavior
On Windows 10 and Ubuntu 18.04 LTS, using same version of GraalVM 20.0.0 java 8 CE, native image building succeed and the given native image work as expected : a SWT window opens with a Hello world message.
On Mac OS, it should work the same way.

Additional context
Don't know if it's the problem, but on MacOS, I had to add the VM option -XstartOnFirstThread in order to make the Java program and the GraalVM agent work :

java -jar target/target/graalvm-swt-native-image-1.0-SNAPSHOT.jar

produces this error :

***WARNING: Display must be created on main thread due to Cocoa restrictions. Use vmarg -XstartOnFirstThread
Exception in thread "main" org.eclipse.swt.SWTException: Invalid thread access
	at org.eclipse.swt.SWT.error(SWT.java:4720)
	at org.eclipse.swt.SWT.error(SWT.java:4635)
	at org.eclipse.swt.SWT.error(SWT.java:4606)
	at org.eclipse.swt.widgets.Display.error(Display.java:1112)
	at org.eclipse.swt.widgets.Display.createDisplay(Display.java:853)
	at org.eclipse.swt.widgets.Display.create(Display.java:837)
	at org.eclipse.swt.graphics.Device.<init>(Device.java:132)
	at org.eclipse.swt.widgets.Display.<init>(Display.java:736)
	at org.eclipse.swt.widgets.Display.<init>(Display.java:727)
	at com.github.mbarbeaux.HelloSWT.main(HelloSWT.java:12)

After adding the -XstartOnFirstThread VM option to the java command, the agent works as expected the SWT window opens correctly and the GraalVM config files are generated. But still the native image fails at build time. I tried to add the option -J-XstartOnFirstThread to the native-image command but it didn't solve the problem.

@mbarbeaux mbarbeaux changed the title JNI error while building native image JNI error while building SWT native image on MacOS Mar 6, 2020
@jramirez-isc jramirez-isc self-assigned this Mar 21, 2020
@mbarbeaux
Copy link
Author

mbarbeaux commented Apr 21, 2020

Ok so I have some kind of update for this ticket.

After many tests, I finally discovered it works as expected if I include the SWT source code manually in my project source directory. The native-image performs the compilation and the executable works fine on MacOS now.

So it seems that, using the official SWT jar file, native-image isn't able to perform the compilation. But if I remove the jar from the classpath and instead copy the SWT source code in my source dir, let maven compile it, create a jar file then execute native image, it works flawlessly.

Don't know what's wrong with the official MacOS cocoa SWT jar, here is the URL of the latest version : https://repo1.maven.org/maven2/org/eclipse/platform/org.eclipse.swt.cocoa.macosx.x86_64/3.114.0/org.eclipse.swt.cocoa.macosx.x86_64-3.114.0.jar

Is it because the jar includes shared libraries ? But it was the same for the Windows and Linux versions of the jar, which both work fine

@Barteks2x
Copy link

I'm running into the same issue on graalvm java 11. Any idea how to fix it when I'm not using maven?

I'm using gradle for build, and I'm running it on github actions.

@mbarbeaux
Copy link
Author

mbarbeaux commented Apr 30, 2020

I got it working successfully on Windows, Linux and MacOS with GraalVM 20.0.0 java 11 version.

I just took the SWT java sources and add them to my project source path (do not use the JAR provided by SWT), run the GraalVM agent to generate config files for JNI, reflection, resources and proxies, and it will work at native compilation time. Of course you will have to also download the SWT native shared libraries and add the "-Dswt.library.path=/path/to/shared/libraries" option when running the native image.

Just take care because SWT sources differ for each operating system.

@Barteks2x
Copy link

Barteks2x commented Apr 30, 2020

I did some more investigation here and it seems like the main difference is that the SWT jar is compiled using the eclipse compiler, and not the standard java compiler. After some further investigation, it seems to be mainly a difference in static initialization order. I was able to reproduce similar issue even at runtime, with the "wrong" initialization order. With that in might it should be possible to force the right initialization order by adding --initialize-at-build-time or forcing intitialization at runtime arguments but testing it is going to take forever because my only access to mac build is through github actions. it's not possible as that would require statically initializing most of SWT at build time.

The first error that actually appear is:

2020-04-30T15:15:35.1196130Z Parsing context:
2020-04-30T15:15:35.1201600Z 	parsing com.oracle.svm.jni.JNIJavaCallWrappers.jniInvoke_VARARGS:Lorg_eclipse_swt_widgets_Display_2_0002eapplicationProc_00028JJJJ_00029J(generated:0)
2020-04-30T15:15:35.1201720Z 
2020-04-30T15:15:35.1201970Z 	at com.oracle.graal.pointsto.util.AnalysisError.parsingError(AnalysisError.java:138)
2020-04-30T15:15:35.1202610Z 	at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:323)
2020-04-30T15:15:35.1202990Z 	at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureParsed(MethodTypeFlow.java:300)
2020-04-30T15:15:35.1203380Z 	at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:107)
2020-04-30T15:15:35.1203780Z 	at com.oracle.graal.pointsto.flow.StaticInvokeTypeFlow.update(InvokeTypeFlow.java:346)
2020-04-30T15:15:35.1204090Z 	at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:511)
2020-04-30T15:15:35.1211560Z 	at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:171)
2020-04-30T15:15:35.1613390Z 	at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
2020-04-30T15:15:35.1614360Z 	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
2020-04-30T15:15:35.1615170Z 	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
2020-04-30T15:15:35.1615330Z 	at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
2020-04-30T15:15:35.1615670Z 	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
2020-04-30T15:15:35.1615860Z 	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
2020-04-30T15:15:35.1616160Z Caused by: org.graalvm.compiler.java.BytecodeParser$BytecodeParserError: org.graalvm.compiler.debug.GraalError: java.lang.reflect.InvocationTargetException
2020-04-30T15:15:35.1636020Z 	at parsing org.eclipse.swt.widgets.Display.applicationProc(Display.java:5620)
2020-04-30T15:15:35.1636380Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.throwParserError(BytecodeParser.java:2582)
2020-04-30T15:15:35.1640430Z 	at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.throwParserError(SharedGraphBuilderPhase.java:94)
2020-04-30T15:15:35.1645450Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3402)
2020-04-30T15:15:35.1659190Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:3204)
2020-04-30T15:15:35.1690950Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:1085)
2020-04-30T15:15:35.1792240Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.buildRootMethod(BytecodeParser.java:979)
2020-04-30T15:15:35.1822800Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.GraphBuilderPhase$Instance.run(GraphBuilderPhase.java:84)
2020-04-30T15:15:35.1823080Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.run(Phase.java:49)
2020-04-30T15:15:35.1823220Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:197)
2020-04-30T15:15:35.1823330Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:42)
2020-04-30T15:15:35.1823460Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:38)
2020-04-30T15:15:35.1823590Z 	at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:221)
2020-04-30T15:15:35.1823720Z 	at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:340)
2020-04-30T15:15:35.1823870Z 	at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:310)
2020-04-30T15:15:35.1824490Z 	... 11 more
2020-04-30T15:15:35.1824690Z Caused by: org.graalvm.compiler.debug.GraalError: java.lang.reflect.InvocationTargetException
2020-04-30T15:15:35.1824840Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.debug.GraalError.shouldNotReachHere(GraalError.java:55)
2020-04-30T15:15:35.1824960Z 	at com.oracle.graal.pointsto.meta.AnalysisMethod.<init>(AnalysisMethod.java:149)
2020-04-30T15:15:35.1825080Z 	at com.oracle.graal.pointsto.meta.AnalysisUniverse.createMethod(AnalysisUniverse.java:412)
2020-04-30T15:15:35.1825180Z 	at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookupAllowUnresolved(AnalysisUniverse.java:400)
2020-04-30T15:15:35.1825320Z 	at com.oracle.graal.pointsto.infrastructure.WrappedConstantPool.lookupMethod(WrappedConstantPool.java:116)
2020-04-30T15:15:35.1825470Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.lookupMethodInPool(BytecodeParser.java:4285)
2020-04-30T15:15:35.1825620Z 	at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.lookupMethodInPool(SharedGraphBuilderPhase.java:107)
2020-04-30T15:15:35.1825760Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.lookupMethod(BytecodeParser.java:4279)
2020-04-30T15:15:35.1825870Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.genInvokeStatic(BytecodeParser.java:1656)
2020-04-30T15:15:35.1826010Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:5288)
2020-04-30T15:15:35.1826150Z 	at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3397)
2020-04-30T15:15:35.1826270Z 	... 22 more
2020-04-30T15:15:35.1829890Z Caused by: java.lang.reflect.InvocationTargetException
2020-04-30T15:15:35.1833520Z 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
2020-04-30T15:15:35.1834000Z 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
2020-04-30T15:15:35.1835630Z 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
2020-04-30T15:15:35.1840050Z 	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
2020-04-30T15:15:35.1840190Z 	at com.oracle.graal.pointsto.meta.AnalysisMethod.<init>(AnalysisMethod.java:147)
2020-04-30T15:15:35.1840340Z 	... 31 more
2020-04-30T15:15:35.1852810Z Caused by: java.lang.ExceptionInInitializerError
2020-04-30T15:15:35.1853260Z 	at org.eclipse.swt.internal.cocoa.Selector.<init>(Selector.java:1393)
2020-04-30T15:15:35.1855820Z 	at org.eclipse.swt.internal.cocoa.Selector.<clinit>(Selector.java:17)
2020-04-30T15:15:35.1857310Z 	at org.eclipse.swt.widgets.Display.$SWITCH_TABLE$org$eclipse$swt$internal$cocoa$Selector(Display.java:104)
2020-04-30T15:15:35.1857490Z 	... 36 more
2020-04-30T15:15:35.1857860Z Caused by: java.lang.NullPointerException
2020-04-30T15:15:35.1858510Z 	at org.eclipse.swt.internal.cocoa.OS.<clinit>(OS.java:66)
2020-04-30T15:15:35.1859400Z 	... 39 more

Later errors are probably caused by this one, so I think they should be ignored until proved otherwise.

The issue boils down to a circular dependency between SWT's OS class and Selector class.

OS class has public static final fiels initialized with Selector.some_enum_value.someField. But Selector is an enum whose constructor invokes a public static method on OS which again wants to statically initialize OS.

This somehow appears to work when OS class is initialized first, and OS is what triggers initialization of Selector, but native-image appears to initialize Selector class without initializing OS class first which triggers the issue. I was able to show the same issue with a simple, small standlone example:

public enum EnumClass {
    VAL1("val1");

    public final String x;
    EnumClass(String param) {
        x = param;
        TestClass.takeEnum(this, param);
    }
}

public class TestClass {
    public static final String VAL = EnumClass.VAL1.x;

    private static java.util.Map<String, EnumClass> VALUES;
    public static void takeEnum(EnumClass e, String s) {
        if (VALUES == null) {
                VALUES = new java.util.HashMap<>();
        }
        VALUES.put(s, e);
    }
}

public class Main {
    public static void main(String... args) {
        System.out.println(TestClass.VAL);
    }
}

Now just if we compile and run it with java, it works just fine. It also works when it's compiled "naively" with native-image.

But in SWT case, the generated configuration causes initializing some classes at build time. In this example, TestClass is the equivalent of OS and EnumClass is the equivalent of Selector. If we force initialization of EnumClass at build time with

native-image.cmd -cp testjar.jar Main -H:+ReportExceptionStackTraces --initialize-at-build-time=EnumClass

we get the following stacktrace:

Error: Class initialization of EnumClass failed. Use the option --initialize-at-run-time=EnumClass to explicitly request delayed initialization of this class.
com.oracle.svm.core.util.UserError$UserException: Class initialization of EnumClass failed. Use the option --initialize-at-run-time=EnumClass to explicitly request delayed initialization of this class.
        at com.oracle.svm.core.util.UserError.abort(UserError.java:79)
        at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.reportInitializationError(ConfigurableClassInitialization.java:202)
        at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.ensureClassInitialized(ConfigurableClassInitialization.java:183)
        at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.forceInitializeHosted(ConfigurableClassInitialization.java:457)
        at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.initializeAtBuildTime(ConfigurableClassInitialization.java:385)
        at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.initializeAtBuildTime(ConfigurableClassInitialization.java:232)
        at com.oracle.svm.hosted.classinitialization.InitKind.lambda$stringConsumer$2(InitKind.java:74)
        at com.oracle.svm.hosted.classinitialization.ClassInitializationFeature.processClassInitializationOptions(ClassInitializationFeature.java:145)
        at com.oracle.svm.hosted.NativeImageGenerator.setupNativeImage(NativeImageGenerator.java:813)
        at com.oracle.svm.hosted.NativeImageGenerator.doRun(NativeImageGenerator.java:528)
        at com.oracle.svm.hosted.NativeImageGenerator.lambda$run$0(NativeImageGenerator.java:445)
        at java.base/java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1407)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: java.lang.ExceptionInInitializerError
        at EnumClass.<init>(EnumClass.java:7)
        at EnumClass.<clinit>(EnumClass.java:2)
        at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized0(Native Method)
        at java.base/jdk.internal.misc.Unsafe.ensureClassInitialized(Unsafe.java:1042)
        at jdk.unsupported/sun.misc.Unsafe.ensureClassInitialized(Unsafe.java:698)
        at com.oracle.svm.hosted.classinitialization.ConfigurableClassInitialization.ensureClassInitialized(ConfigurableClassInitialization.java:167)
        ... 14 more
Caused by: java.lang.NullPointerException
        at TestClass.<clinit>(TestClass.java:2)
        ... 20 more

Which is exactly what the issue is in case of SWT, but in different stage of compilation (because I'm forcing it with a parameter, and in case of SWT it's indirectly forced by configuration)

I'm going to investigate further but this is what I found so far.

@Barteks2x
Copy link

Barteks2x commented Apr 30, 2020

The main difference that I can see in the bytecode, is that eclipse compiler generates a synthetic method that initializes tableswitch map, while javac compiles it to an entire synthetic class where the data is initialized statically.

With this in mind, I got a small self contained case that reproduces the issue:

// EnumClass.class
public enum EnumClass {
    VAL1("val1");

    public final String x;
    EnumClass(String param) {
        x = param;
        TestClass.takeEnum(this, param);
    }
    static EnumClass value(String s) {
        return TestClass.getEnum(s);
    }
}


// Main.class
import java.lang.reflect.*;

public class Main {
    public static void main(String... args) throws Throwable { // used reflection here to generate configuration that I then reused as "jni" config
        System.out.println(TestClass.getEnum("val1"));
        Method m = Main.class.getDeclaredMethod("doThing", String.class);
        System.out.println(m.invoke(null, "val1"));
    }

    static long doThing(String s) {
        switch (EnumClass.value(s)) {
            case VAL1: return 0;
            default: return -1;
        }
    }
}

// TestClass.class
public class TestClass {
    public static final String VAL = EnumClass.VAL1.x;

    private static java.util.Map<String, EnumClass> VALUES;
    public static void takeEnum(EnumClass e, String s) {
        if (VALUES == null) {
                VALUES = new java.util.HashMap<>();
        }
        VALUES.put(s, e);
    }
    public static EnumClass getEnum(String s) { return VALUES.get(s); }
}

Then I add this to jni config json file:

[
{
  "name":"Main",
  "methods":[{"name":"doThing","parameterTypes":["java.lang.String"] }]
}
]

If the code is compiled with javac, it works fine. If it's compiled with ecj, it fails with the following error:

[main:14188]    classlist:   2,402.71 ms,  1.00 GB
[main:14188]        (cap):   2,860.41 ms,  1.36 GB
[main:14188]        setup:   5,336.81 ms,  1.36 GB
[main:14188]     analysis:   3,630.49 ms,  1.36 GB
Fatal error: com.oracle.graal.pointsto.util.AnalysisError$ParsingError: Error encountered while parsing Main.doThing(java.lang.String)
Parsing context:
        parsing com.oracle.svm.reflect.Main_doThing_0a53730d28337e862e8ecdbb5a8053b0ef3e3d13_1.invoke(Unknown Source)
        parsing java.lang.reflect.Method.invoke(Method.java:566)
        parsing Main.main(Main.java:7)
        parsing com.oracle.svm.core.JavaMainWrapper.runCore(JavaMainWrapper.java:151)
        parsing com.oracle.svm.core.JavaMainWrapper.run(JavaMainWrapper.java:186)
        parsing com.oracle.svm.core.code.IsolateEnterStub.JavaMainWrapper_run_5087f5482cc9a6abc971913ece43acb471d2631b(generated:0)

        at com.oracle.graal.pointsto.util.AnalysisError.parsingError(AnalysisError.java:138)
        at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:323)
        at com.oracle.graal.pointsto.flow.MethodTypeFlow.ensureParsed(MethodTypeFlow.java:300)
        at com.oracle.graal.pointsto.flow.MethodTypeFlow.addContext(MethodTypeFlow.java:107)
        at com.oracle.graal.pointsto.flow.StaticInvokeTypeFlow.update(InvokeTypeFlow.java:346)
        at com.oracle.graal.pointsto.BigBang$2.run(BigBang.java:511)
        at com.oracle.graal.pointsto.util.CompletionExecutor.lambda$execute$0(CompletionExecutor.java:171)
        at java.base/java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec(ForkJoinTask.java:1426)
        at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
        at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
        at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
        at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
        at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:177)
Caused by: org.graalvm.compiler.java.BytecodeParser$BytecodeParserError: org.graalvm.compiler.debug.GraalError: java.lang.reflect.InvocationTargetException
        at parsing Main.doThing(Main.java:12)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.throwParserError(BytecodeParser.java:2582)
        at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.throwParserError(SharedGraphBuilderPhase.java:94)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3402)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBlock(BytecodeParser.java:3204)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.build(BytecodeParser.java:1085)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.buildRootMethod(BytecodeParser.java:979)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.GraphBuilderPhase$Instance.run(GraphBuilderPhase.java:84)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.run(Phase.java:49)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.BasePhase.apply(BasePhase.java:197)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:42)
        at jdk.internal.vm.compiler/org.graalvm.compiler.phases.Phase.apply(Phase.java:38)
        at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.parse(MethodTypeFlowBuilder.java:221)
        at com.oracle.graal.pointsto.flow.MethodTypeFlowBuilder.apply(MethodTypeFlowBuilder.java:340)
        at com.oracle.graal.pointsto.flow.MethodTypeFlow.doParse(MethodTypeFlow.java:310)
        ... 11 more
Caused by: org.graalvm.compiler.debug.GraalError: java.lang.reflect.InvocationTargetException
        at jdk.internal.vm.compiler/org.graalvm.compiler.debug.GraalError.shouldNotReachHere(GraalError.java:55)
        at com.oracle.graal.pointsto.meta.AnalysisMethod.<init>(AnalysisMethod.java:149)
        at com.oracle.graal.pointsto.meta.AnalysisUniverse.createMethod(AnalysisUniverse.java:412)
        at com.oracle.graal.pointsto.meta.AnalysisUniverse.lookupAllowUnresolved(AnalysisUniverse.java:400)
        at com.oracle.graal.pointsto.infrastructure.WrappedConstantPool.lookupMethod(WrappedConstantPool.java:116)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.lookupMethodInPool(BytecodeParser.java:4285)
        at com.oracle.svm.hosted.phases.SharedGraphBuilderPhase$SharedBytecodeParser.lookupMethodInPool(SharedGraphBuilderPhase.java:107)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.lookupMethod(BytecodeParser.java:4279)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.genInvokeStatic(BytecodeParser.java:1656)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.processBytecode(BytecodeParser.java:5288)
        at jdk.internal.vm.compiler/org.graalvm.compiler.java.BytecodeParser.iterateBytecodesForBlock(BytecodeParser.java:3397)
        ... 22 more
Caused by: java.lang.reflect.InvocationTargetException
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at com.oracle.graal.pointsto.meta.AnalysisMethod.<init>(AnalysisMethod.java:147)
        ... 31 more
Caused by: java.lang.ExceptionInInitializerError
        at EnumClass.<init>(EnumClass.java:7)
        at EnumClass.<clinit>(EnumClass.java:2)
        at Main.$SWITCH_TABLE$EnumClass(Main.java:3)
        ... 36 more
Caused by: java.lang.NullPointerException
        at TestClass.<clinit>(TestClass.java:2)
        ... 39 more
Error: Image build request failed with exit status 1

For completeness, here is bytecode comparison:
ecj: https://gist.github.com/Barteks2x/ba88cbcfb5f162d585f3312f556f1abd
javac: https://gist.github.com/Barteks2x/1dcf3c7d279c76cf20ff966fff30a8a7
diff -u -r src_javac src_ecj https://gist.github.com/Barteks2x/9e1c8269d093de188b73bde0e225c8ee

@christianwimmer
Copy link
Member

I think @vjovanov is currently working on a fix for this

@oubidar-Abderrahim
Copy link
Member

@christianwimmer FYI: There is an Internal ticket (GR-24133) for this issue

@igortat
Copy link

igortat commented Nov 24, 2023

Any progress with this issue?

@wirthi wirthi changed the title JNI error while building SWT native image on MacOS [GR-24133] JNI error while building SWT native image on MacOS Apr 29, 2024
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

7 participants