Closed pshipton closed 2 months ago
Test case
public class MaxChar {
private final static int MAX_UTF16_STRING_LENGTH = Integer.MAX_VALUE / 2;
private static char[] generateCharData(int size) {
char[] nonAscii = "\u0100".toCharArray();
char[] arr = new char[size];
System.arraycopy(nonAscii, 0, arr, 0, nonAscii.length); // non-latin1 at start
return arr;
}
public static void main(String[] args) throws Throwable {
final char[] large_char_array = generateCharData(MAX_UTF16_STRING_LENGTH + 1);
int[] sizes = new int[] {
MAX_UTF16_STRING_LENGTH + 1,
MAX_UTF16_STRING_LENGTH,
MAX_UTF16_STRING_LENGTH - 1};
for (int size : sizes) {
try {
new String(large_char_array, 0, size);
if (size >= MAX_UTF16_STRING_LENGTH) {
System.out.println("Expected OOM for " + size);
}
} catch (OutOfMemoryError e) {
System.out.println(e);
}
}
}
}
When running with -Xcomp
(-Xjit:count=0
) on at least aarch64 or x86, the OOM which is expected for size 1073741823 doesn't occur. It didn't fail on zlinux, some platforms (AIX, Windows) didn't run.
@hzongaro pls take a look
This does seem related to https://github.com/eclipse-openj9/openj9/issues/19309 after all.
In JDK 21 and earlier, the implementation of StringUTF16.newBytesFor
tested whether the length was greater than 0x3fffffff. If so, it would throw an OutOfMemoryError
.
In JDK 23, the implementation of StringUTF16.newBytes
, by way of String.UTF16.newBytesLength
, will throw an OutOfMemoryError
for length values greater than or equal to 0x3fffffff.
The IL the JIT compiler is generating is consistent with the expectation that an OutOfMemoryError
will not be thrown for a length of 0x3fffffff. Before I make any further changes to the JIT compiler, is the inconsistency between the different JDK versions expected, or is one of them a bug?
It looks like the handling of a length of 0x3fffffff was deemed to be a bug, and the change in behaviour was introduced in JDK Level 23 in commit https://github.com/ibmruntimes/openj9-openjdk-jdk23/commit/38f0d53b1aacab53193885064fa3723e26b326f8.
I will update the JIT compiler's handling of this by falling back to the out-of-line call to StringUTF16.toBytes
for lengths outside the range [0,0x3ffffffe]. That way, if the bug is ever fixed in other JDK levels, the JIT-compiled code will not show any difference in behaviour to interpreted bytecode.
Reopening, as I will need to port the fix to the v0.47.0-release and v0.48.0-release branches
Opened pull requests #20077 and #20078 to port the fix to the v0.47.0-release and v0.48.0-release branches
https://openj9-jenkins.osuosl.org/job/Test_openjdk23_j9_sanity.openjdk_aarch64_mac_Nightly_testList_0/13/ jdk_lang_1 (-XX:-UseCompressedOops)
-Xcomp (-Xjit:count=0) -Xmx8g
java/lang/String/CompactString/MaxSizeUTF16String.javahttps://openj9-jenkins.osuosl.org/job/Test_openjdk23_j9_sanity.openjdk_x86-64_linux_Nightly_testList_1/38/ jdk_lang_1
https://openj9-jenkins.osuosl.org/job/Test_openjdk23_j9_sanity.openjdk_x86-64_mac_Nightly_testList_0/11 jdk_lang_0, jdk_lang_j9_0 https://openj9-jenkins.osuosl.org/job/Test_openjdk23_j9_sanity.openjdk_x86-64_mac_Nightly_testList_1/11/ jdk_lang_1