On Fri, 14 Nov 2025 04:46:26 GMT, Shaojin Wen <[email protected]> wrote:
>> This PR introduces a new efficient API for appending two-digit integers to
>> StringBuilders and refactors DateTimeHelper to leverage this new
>> functionality.
>>
>> Changes include:
>>
>> 1. New `appendPair` method for efficient two-digit integer formatting
>> (00-99):
>> - Added `AbstractStringBuilder.appendLatin1(char c1, char c2)` with core
>> implementation
>> - Added `JavaLangAccess.appendPair(StringBuilder, char c1, char c2)` for
>> internal access
>> - Added `DecimalDigits.appendPair(StringBuilder, int)` public static
>> utility method
>> - Enhanced Javadoc documentation for all new methods
>>
>> 2. Refactored `DateTimeHelper` to use the new `DecimalDigits.appendPair`:
>> - Updated `DateTimeHelper.formatTo` methods for `LocalDate` and
>> `LocalTime`
>> - Replaced manual formatting logic with the new efficient two-digit
>> appending
>> - Improved code clarity and consistency in date/time formatting
>>
>> These changes improve code clarity and performance when formatting two-digit
>> numbers, particularly in date/time formatting scenarios.
>
> Shaojin Wen has updated the pull request incrementally with one additional
> commit since the last revision:
>
> remove JLA
I wanted to modify the DecimalDigits.appendQuad method as follows, but this
caused `MergeStore` to not work.
public static void appendQuad(StringBuilder buf, int v) {
// The & 0x7f operation keeps the index within the safe range [0, 127]
for the DIGITS array,
// which allows the JIT compiler to eliminate array bounds checks for
performance.
int packed = DIGITS[(v / 100) & 0x7f] | (DIGITS[(v % 100) & 0x7f] <<
16);
// The temporary String and byte[] objects created here are typically
eliminated
// by the JVM's escape analysis and scalar replacement optimizations
during
// runtime compilation, avoiding actual heap allocations in optimized
code.
buf.append(
JLA.uncheckedNewStringWithLatin1Bytes(
new byte[] {(byte) packed, (byte) (packed >> 8),
(byte) (packed >> 16), (byte) (packed >>
24)}));
}
The output is as follows:
[TraceMergeStores] MergePrimitiveStores::run: 868 StoreB === 887 813 861 145
[[ 872 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 848 StoreB === 888 813 840 81
[[ 853 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 559 StoreB === 548 543 351 352
[[ 562 ]] @java/lang/AbstractStringBuilder
(java/lang/CharSequence,java/lang/Appendable)+16 *, name=coder, idx=13;
Memory: @java/lang/StringBuilder
(java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):NotNull:exact+16
*, name=coder, idx=13; !jvms: AbstractStringBuilder::append @ bci:78 (line
651) StringBuilder::append @ bci:2 (line 179) DecimalDigits::appendQuad @
bci:68 (line 496)
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 739 StoreI === 879 813 354 456
[[ 17 ]] @java/lang/AbstractStringBuilder
(java/lang/CharSequence,java/lang/Appendable)+12 *, name=count, idx=14;
Memory: @java/lang/StringBuilder
(java/io/Serializable,java/lang/Comparable,java/lang/CharSequence,java/lang/Appendable):NotNull:exact+12
*, name=count, idx=14; !jvms: AbstractStringBuilder::append @ bci:95 (line
654) StringBuilder::append @ bci:2 (line 179) DecimalDigits::appendQuad @
bci:68 (line 496)
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 872 StoreB === 887 868 856 912
[[ 876 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 853 StoreB === 888 848 851 906
[[ 858 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 858 StoreB === 888 853 856 912
[[ 863 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 863 StoreB === 888 858 861 145
[[ 880 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 876 StoreB === 887 872 851 906
[[ 878 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
[TraceMergeStores] MergePrimitiveStores::run: 878 StoreB === 887 876 840 81
[[ 880 ]] @byte[int:>=0]
(java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *, idx=7; Memory:
@byte[int:>=0] (java/lang/Cloneable,java/io/Serializable):NotNull:exact+any *,
idx=7;
[TraceMergeStores] expect no use: None
[TraceMergeStores] expect def: None
-------------
PR Comment: https://git.openjdk.org/jdk/pull/26911#issuecomment-3531435995