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
Image files are not displayed properly on SwingSet2 demo program #4193
Comments
Will investigate to see what happens. |
I already reproduced the issue with OpenJDK11/OpenJ9 on LinuxLite (downloaded from https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.1%2B13/OpenJDK11U-jdk_x64_linux_openj9_jdk-11.0.1_13_openj9-0.11.0_11.0.1_13.tar.gz) and It works good with OpenJDK11/Hotspot on LinuxLite (downloaded from https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.1%2B13/OpenJDK11U-jdk_x64_linux_hotspot_11.0.1_13.tar.gz) So it looks like there is something wrong happening in our code which needs further analysis. |
Does it still occur with -Xint? |
Investigation shows the interlaceflag in Test2 (the original code in SwingSet2) was set to false during reading the image via readImage() at src/java.desktop/share/classes/sun/awt/image/ImageDecoder.java (OpenJDK11)
The debugging messages are as follows:
However, the value of the passed-in interlace flag was messed up when calling the native code GifImageDecoder.parseImage() at src/java.desktop/share/native/libawt/awt/image/gif/gifdecoder.c
So I tried to hack the native code Java_sun_awt_image_GifImageDecoder_parseImage() by forcing passinc to 1 (assuming interlace is false) and picture was correctly generated as follows: Based on the investigation above, It seems there is some issue with manipulation on boolean value in JNI & bytecode interpreter in our code which needs to be fixed (Specifically the problem happens when converting from boolean (Java level) to jint (native) via JNI) FYI: @DanHeidinga, @tajila |
Just talked to Tobi, it seems there was no change with the passed-in arguments that got merged. Given that the problem happened in the JNI native, need to double-check the calling path from java to native (runJNINative, callCFunction, e.g) to figure out how the passe-in arguments were handled. |
The root cause of the issue is due to the inconsistency of the argument type between the declaration in java code and the corresponding implementation in the native code in OpenJDK11 as follows: src/java.desktop/share/classes/sun/awt/image/GifImageDecoder.java
src/java.desktop/share/native/libawt/awt/image/gif/gifdecoder.c
Technically, this issue has nothing to do with VM (from cJNICallout) or FFI in JNI operation as the FFI code depends on the size of type in the declaration to copy the value from the java stack to the native. Thus, changing "jint interlace" to "jboolean interlace" fixes the issue and the GIF image will be generated correctly as as result. @DanHeidinga , I wondering whether we can request Oracle/OpenJDK to update the incorrect argument type for Java_sun_awt_image_GifImageDecoder_parseImage() in Java11 as this makes more sense from JNI perspective. |
@andrew-m-leonard can you propose a patch at OpenJDK addressing the mismatch between the java & native signatures? Bonus points if it can be backported to JDK11 |
@ChengJin01 , could you explain why Linux ppc64le, s390x and AIX build don't have this issue ? |
@takiguc, this entirely depends on how the target platform extends or casts from boolean (1byte) to int (e.g. 4bytes) on the native stack (this also depends on whether it is big-endian, in which case we will help to extend in VM). Technically the argument types should be identical on both java and native from JNI perspective. Relying on the automatic cast/conversion on platforms is dangerous in such case. |
I am still double-checking the related VM & FFI code on X86 (UNIX-based) to see whether we can figure out a way around the issue against the VM Spec as to the manipulation on the boolean type. |
Created openjdk bug : https://bugs.openjdk.java.net/browse/JDK-8217735 |
Further investigation on the FFI code (X86) shows the problem was caused by the aligned memory without initialization before copying arguments the native stack as follows:
So it means all arguments on the stack are aligned at 8 bytes (already verify the address of argp) e.g. if the current stack pointer argp stores the boolean value (1 byte) at 0x28117640, the next value to be copied starts at 0x28117648.
In such case, casting the boolean type (1 byte ) to the int type (4 bytes) inevitably introduces the garbage data (random value) existing in the allocated memory. |
Technically there are two solutions to the issue on our side.
The idea is to ensure there is no garbage data introduced in casting short-size types to long-size types (e.g. from boolean to int) |
[2] replace the FFI type of boolean (1 byte) to with the FFI type of int (4 bytes) The idea is based on the VM Spec which says:
From VM Spec perspective, the int type for boolean in the native is acceptable at this point.
In such case, the boolean type always takes 4 bytes on the java stack for arguments (actually the initialization has been done by its own assignment rather than in FFI code) |
The only difference is that solution [1] is specific to X86 on which the issue was originally detected and has no impact on other platform, while solution [2] affects all platforms (theoretically solution [2] should work on all platforms) So we can choose either of these two solutions above to fix the issue on our side if Oracle insists on the jint type. @DanHeidinga, any preference on the solutions above? |
@ChengJin01 there's been recent changes to return bytecodes, |
I've created a simple test to verify the assumption above to see how it goes with a passed-in int value in the case of the boolean argument in the native (the .class file was generated via ASM as javac refuses to convert int to boolean in the code level)
JniBoolArgTest.c
[1] result on OpenJ9
[2] result on Hotspot
So Both OpenJ9 and Hotspot ended up with the same incorrect result as the conversion won't happen automatically in the case of boolean. |
The conversion can be done on the java stack before copying the arguments to the native
The only concern is the fix changes the original passed-in value on the java stack; otherwise we have to address the conversion after the copy in the FFI code specific to all platforms, which seems complicated. |
indicates that JNI code processing booleans should only ever read a char's worth of data so uint8 is correct. Given this bug though, I'm leaning towards the solution in #4193 (comment) but using @ChengJin01 Can you confirm that passes the test? |
@DanHeidinga , Changing to ffi_type_uint32 for boolean only fixes the case of int type in the native (the issue with GIF image) but can't address the case of a random int value (1 byte) to be passed as boolean to the native. The reason is that it assumes the original value is 1 type (the same as solution [1]) , in which case there is no conversion from 1 byte int value (e.g. 0x7e) to 0 or 1. |
Some JNI native tests (detected in personal build) with boolean return type shows changing to ffi_type_uint32 affects the return value for boolean. Need to check what happened in such case. |
@andrew-m-leonard Can you put the fix for this into the Extensions repos? I'd like to ensure we have the right behaviour while we finish reviewing this PR |
Tagged against the 0.13 milestone as a reminder to get the extensions change into this release. |
I've raised the question on the awt-dev maillist to get Oracle's position... https://mail.openjdk.java.net/pipermail/awt-dev/2019-March/015029.html |
A fix to the JNI declaration has been merged to jdk12. |
JNI fix merged for jdk8, 11, next. |
The change is to ensure booleans can be handled appropriately as the int type when calling the JNI natives. Close: eclipse-openj9#4193 Signed-off-by: CHENGJin <jincheng@ca.ibm.com>
Merged into openjdk http://hg.openjdk.java.net/jdk/client/rev/62171da145f9 |
Hello.
I used OpenJDK JDK11 + OpenJ9 for Linux amd64.
When I executed SwingSet2 demo, GIF images were not displayed properly.
And the situation was random, 4 GIF images were displayed on JInternalFrame Demo.
2 or 3 images were broken.
Version Information: RHEL 7.5
Test instruction:
This issue only happens on Linux amd64.
Linux ppc64le and s390x builds were OK.
It worked fine on following AdoptOpenJDK build.
It seemed GIF image treated as interlace GIF.
But I checked interlace flag on GIF.
I checked the latest IBM Java8 for Linux amd64, but I could not recreate this issue.
I assume IBM Java8 applied a fix against class library on GIF image decoder related code.
But it seems register or memory area was not clean up properly.
The text was updated successfully, but these errors were encountered: