RFR: 8366224: Introduce DecimalDigits.appendPair for efficient two-digit formatting and refactor DateTimeHelper [v22]
Shaojin Wen
swen at openjdk.org
Fri Nov 14 08:03:20 UTC 2025
On Fri, 14 Nov 2025 04:46:26 GMT, Shaojin Wen <swen at openjdk.org> 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
More information about the core-libs-dev
mailing list