Possible bug: compiler generating `ldc` instead of `sipush` and `iconst_m1` for characters in range [32768; 65535]
JARvis PROgrammer
mrjarviscraft at gmail.com
Thu Aug 8 17:16:05 UTC 2019
Hi there, it seems that the javac compiler generates non-optimal bytecode
for pushing values of (compile-time) type `char`.
In order to test it I've first written a class which has a method accepting
`char`s which writes them to a file (so that results can be easily
compared):
private static void consumeChar(final char character) throws IOException {
try (final BufferedWriter writer = new BufferedWriter(new
FileWriter(new File("Javac.txt"), true))) {
writer.write(Character.toString(character));
}
}
And then added code to `main` which simply invokes this method for all
corner cases and nearby char values {(char) 0, (char) 1, (char) 2, (char)
3, (char) 4, (char) 5, (char) 6, (char) 7, (char) 126, (char) 127, (char)
128, (char) 129, (char) 32766, (char) 32767, (char) 32768, (char) 32769,
(char) 65534, (char) 65535}. After this the class was compiled using
`javac` (both tested on release 11 and early-access 13).
The resulting bytecode uses *iconst#* for range [(char) 0; (char) 5],
*bipush* for range from [(char) 6; (char) 127], *sipush* for range
[(char) 128; (char) 32767] and (strangely) *ldc* for range [(char) 32768;
(char) 65535].
In order to check if the strange behavour is not the only way to achieve
pushing "big" `char` values onto the stack, I've recreated the similar
class using ObjectWeb ASM using *iconst_m1* instruction for pusing ((char)
65535) and *sipush* (with negative values) for pushing values of range
[(char) 32768; (char) 65534].
The following function describes this behaviour:
private static void pushChar(final MethodVisitor method, final int charCode) {
switch (charCode) {
case 65535: {
method.visitInsn(ICONST_M1);
break;
}
case 1: {
method.visitInsn(ICONST_1);
break;
}
case 2: {
method.visitInsn(ICONST_2);
break;
}
case 3: {
method.visitInsn(ICONST_3);
break;
}
case 4: {
method.visitInsn(ICONST_4);
break;
}
case 5: {
method.visitInsn(ICONST_5);
break;
} default: {
if (charCode <= Byte.MAX_VALUE) method.visitIntInsn(BIPUSH, charCode
else method.visitIntInsn(SIPUSH, (short) charCode);
}
}
}
(PS, in theory, *bipush* might also be aplicable for some values where
*sipush* is used, but I didn't test it)
The generated class once run via java (release 11 and early-access 13 were
used) generated the file with content equal to the one of the
javac-compiled class.
And so, it seems to be a bug that `javac` uses *ldc* instruction instead of
more primitive ones while those may handle all range of characters.
All files used for test purposes (including javap call results) are
attached to this message:
JavacMain.java - source code of class compiled via javac
JavacMain.class - compiled JavacMain.java (javac -g:none --enable-preview)
JavacMain.javap - disassembled JavacMain.class (javac -v -p -s -c)
Javac.txt - file written by running JavacMain.class
AsmMain_Generator.java - source code of class generating AsmMain.class
AsmMain.class - generated replica of JavacMain.class using *iconst_m1*
instruction
for pusing ((char) 65535) and *sipush* (with negative values) for pushing
values of range [(char) 32768; (char) 65534]
Asm Main.javap - disassembled AsmMain.class (javac -v -p -s -c)
Asm.txt - file written by running AsmMain.class
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190808/32126599/attachment-0001.html>
-------------- next part --------------
~????????
-------------- next part --------------
A non-text attachment was scrubbed...
Name: JavacMain.java
Type: application/octet-stream
Size: 1190 bytes
Desc: not available
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190808/32126599/JavacMain-0001.java>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: JavacMain.class
Type: application/octet-stream
Size: 904 bytes
Desc: not available
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190808/32126599/JavacMain-0001.class>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: JavacMain.javap
Type: application/octet-stream
Size: 8513 bytes
Desc: not available
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190808/32126599/JavacMain-0001.javap>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: AsmMain_Generator.java
Type: application/octet-stream
Size: 9158 bytes
Desc: not available
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190808/32126599/AsmMain_Generator-0001.java>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: AsmMain.class
Type: application/octet-stream
Size: 883 bytes
Desc: not available
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190808/32126599/AsmMain-0001.class>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: AsmMain.javap
Type: application/octet-stream
Size: 8252 bytes
Desc: not available
URL: <https://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20190808/32126599/AsmMain-0001.javap>
-------------- next part --------------
~????????
More information about the compiler-dev
mailing list