RFR: 8355177: Speed up StringBuilder::append(char[]) via Unsafe::copyMemory [v5]
Roger Riggs
rriggs at openjdk.org
Tue Jun 24 21:24:35 UTC 2025
On Sat, 10 May 2025 11:20:35 GMT, Shaojin Wen <swen at openjdk.org> wrote:
>> In BufferedReader.readLine and other similar scenarios, we need to use StringBuilder.append(char[]) to build the string.
>>
>> For these scenarios, we can Unsafe.copyMemory instead of the character copy of the char-by-char loop to improve the speed.
>>
>> @RogerRiggs completed the optimization when the encoder is LATIN1 in PR #24967. This PR continues to complete the optimization when the encoder is UTF16.
>
> Shaojin Wen has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains nine commits:
>
> - copyright
> - Merge remote-tracking branch 'upstream/master' into optim_sb_append_chars_202504
>
> # Conflicts:
> # src/java.base/share/classes/java/lang/AbstractStringBuilder.java
> - Merge remote-tracking branch 'upstream/master' into optim_sb_append_chars_202504
>
> # Conflicts:
> # src/java.base/share/classes/java/lang/AbstractStringBuilder.java
> - Merge remote-tracking branch 'upstream/master' into optim_sb_append_chars_202504
>
> # Conflicts:
> # src/java.base/share/classes/java/lang/StringUTF16.java
> - putCharsUnchecked
> - copyright
> - Using StringUTF16.compress to speed up LATIN1 StringBuilder append(char[])
> - Using Unsafe.copyMemory to speed up UTF16 StringBuilder append(char[])
> - add append(char[]) benchmark
Changes requested by rriggs (Reviewer).
src/java.base/share/classes/java/lang/StringUTF16.java line 1494:
> 1492: checkBoundsBeginEnd(index, index + end - off, val);
> 1493: checkBoundsBeginEnd(off, end, ca);
> 1494: putCharsUnchecked(val, index, ca, off, end);
There is no reason to separate the bounds checks from the call to Unsafe.copyMemory.
Remove `putCharsUnchecked` and inline the call here.
Do not be tempted to use it more broadly and make the bounds checks harder to audit.
src/java.base/share/classes/java/lang/StringUTF16.java line 1668:
> 1666: private static void checkBoundsBeginEnd(int begin, int end, char[] val) {
> 1667: String.checkBoundsBeginEnd(begin, end, val.length);
> 1668: }
This method doesn't pull it weight, inline the check with the singular use.
test/micro/org/openjdk/bench/java/lang/StringBuilders.java line 285:
> 283: @Benchmark
> 284: public int appendWithCharArrayLatin1() {
> 285: StringBuilder buf = sbLatin1;
Do not re-use the sbLatin1 buffer, its length may have changed by previous tests and perturb the test results.
test/micro/org/openjdk/bench/java/lang/StringBuilders.java line 295:
> 293: @Benchmark
> 294: public int appendWithCharArrayUTF16() {
> 295: StringBuilder buf = sbUtf16;
Do not re-use the sbUtf16 buffer, its length may have changed by previous tests and perturb the test results.
-------------
PR Review: https://git.openjdk.org/jdk/pull/24773#pullrequestreview-2955366637
PR Review Comment: https://git.openjdk.org/jdk/pull/24773#discussion_r2164925190
PR Review Comment: https://git.openjdk.org/jdk/pull/24773#discussion_r2164930261
PR Review Comment: https://git.openjdk.org/jdk/pull/24773#discussion_r2164931643
PR Review Comment: https://git.openjdk.org/jdk/pull/24773#discussion_r2164933643
More information about the core-libs-dev
mailing list