On Mon, 17 Jun 2024 04:58:41 GMT, Shaojin Wen <d...@openjdk.org> wrote:

>> The current versions of FloatToDecimal and DoubleToDecimal allocate 
>> additional objects. Reducing these allocations can improve the performance 
>> of Float/Double.toString and AbstractStringBuilder's append(float/double).
>> 
>> This patch is just a code refactoring to reduce object allocation, but does 
>> not change the Float/Double to decimal algorithm.
>> 
>> The following code comments the allocated objects to be removed.
>> 
>> 
>> class FloatToDecimal {
>>     public static String toString(float v) {
>>         // allocate object FloatToDecimal
>>         return new FloatToDecimal().toDecimalString(v);
>>     }
>> 
>>     public static Appendable appendTo(float v, Appendable app)
>>             throws IOException {
>>         // allocate object FloatToDecimal
>>         return new FloatToDecimal().appendDecimalTo(v, app);
>>     }
>> 
>>     private Appendable appendDecimalTo(float v, Appendable app)
>>             throws IOException {
>>         switch (toDecimal(v)) {
>>             case NON_SPECIAL:
>>                 // allocate object char[]
>>                 char[] chars = new char[index + 1];
>>                 for (int i = 0; i < chars.length; ++i) {
>>                     chars[i] = (char) bytes[i];
>>                 }
>>                 if (app instanceof StringBuilder builder) {
>>                     return builder.append(chars);
>>                 }
>>                 if (app instanceof StringBuffer buffer) {
>>                     return buffer.append(chars);
>>                 }
>>                 for (char c : chars) {
>>                     app.append(c);
>>                 }
>>                 return app;
>>             // ...
>>         }
>>     }
>> }
>> 
>> class DoubleToDecimal {
>>     public static String toString(double v) {
>>         // allocate object DoubleToDecimal
>>         return new DoubleToDecimal(false).toDecimalString(v);
>>     }
>> 
>>     public static Appendable appendTo(double v, Appendable app)
>>             throws IOException {
>>         // allocate object DoubleToDecimal
>>         return new DoubleToDecimal(false).appendDecimalTo(v, app);
>>     }
>> 
>>     private Appendable appendDecimalTo(double v, Appendable app)
>>             throws IOException {
>>         switch (toDecimal(v, null)) {
>>             case NON_SPECIAL:
>>                 // allocate object char[]
>>                 char[] chars = new char[index + 1];
>>                 for (int i = 0; i < chars.length; ++i) {
>>                     chars[i] = (char) bytes[i];
>>                 }
>>             ...
>
> Shaojin Wen has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Utf16 case remove `append first utf16 char`

src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java line 43:

> 41: public final class DoubleToDecimal extends ToDecimal {
> 42:     /**
> 43:      * Use LATIN1 encoding to process the input byte[] str

Suggestion:

     * Use LATIN1 encoding to process the in-out byte[] str

src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java line 49:

> 47: 
> 48:     /**
> 49:      * Use UTF16 encoding to process the input byte[] str

Suggestion:

     * Use UTF16 encoding to process the in-out byte[] str

src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java line 175:

> 173:      */
> 174:     public int putDecimal(byte[] str, int index, double v) {
> 175:         assert index >= 0 && index + MAX_CHARS <= length(str) : "Trusted 
> caller missed bounds check";

Suggestion:

        assert 0 <= index && index <= length(str) - MAX_CHARS : "Trusted caller 
missed bounds check";

This avoids a potential overflow.
But if you want to enforce the check, you should probably avoid using `assert` 
since assertions might be disabled.

src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java line 236:

> 234:                     dk = -1;
> 235:                 }
> 236:                 return toDecimal(str, index, Q_MIN, t, dk, fd) - start;

I suggest restoring the original logic like so:

                /* subnormal value */
                return (t < C_TINY
                        ? toDecimal(str, index, Q_MIN, 10 * t, -1, fd)
                        : toDecimal(str, index, Q_MIN, t, 0, fd)) - start;

src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java line 452:

> 450:         if (l != 0) {
> 451:             put8Digits(str, index, l);
> 452:             index += 8;

As discussed in `ToDecimal`, all `put...` methods should return the updated 
`index`. Then this code can be rewritten as
Suggestion:

            index = put8Digits(str, index, l);

so that the caller doesn't need to know how many characters were added.

src/java.base/share/classes/jdk/internal/math/DoubleToDecimal.java line 460:

> 458:         putChar(str, index++, 'E');
> 459:         if (e < 0) {
> 460:             putChar(str, index++, '-');

By the same logic as suggested above for `put8Digits`
Suggestion:

            index = putChar(str, index, '-');


and other places as well.

src/java.base/share/classes/jdk/internal/math/FloatToDecimal.java line 41:

> 39:  * This class exposes a method to render a {@code float} as a string.
> 40:  */
> 41: public final class FloatToDecimal extends ToDecimal {

The review of this class is the same as for `DoubleToDecimal`, so I won't 
repeat it here.

src/java.base/share/classes/jdk/internal/math/ToDecimal.java line 34:

> 32: import static java.lang.Math.multiplyHigh;
> 33: 
> 34: sealed class ToDecimal permits DoubleToDecimal, FloatToDecimal {

I think this should better be

Suggestion:

abstract sealed class ToDecimal permits DoubleToDecimal, FloatToDecimal {


since we don't want/need to instantiate this class.

src/java.base/share/classes/jdk/internal/math/ToDecimal.java line 45:

> 43:     static final int PLUS_INF    = 0x300;
> 44:     static final int MINUS_INF   = 0x400;
> 45:     static final int NAN         = 0x500;

These constants could be like the original ones (0, 1, 2, ...).
This would make the switch over them a `tableswitch` rather than a 
`lookupswitch` in bytecode. I'm not sure whether this would improve machine 
code, however.
Of course, logic would need to be changed in some places (`<< 8`, `>>> 8`, etc.)

src/java.base/share/classes/jdk/internal/math/ToDecimal.java line 63:

> 61:     }
> 62: 
> 63:     final void putChar(byte[] str, int index, int c) {

I think it would be better for all the `put...` methods here to return the 
updated `index`, hence replacing the return type from `void` to `int`.

This would make usages easier, as there's no need to remember at the call sites 
by how much the index must be incremented after the usage.

src/java.base/share/classes/jdk/internal/math/ToDecimal.java line 71:

> 69:     }
> 70: 
> 71:     final void putCharsAt(byte[] str, int index, int c1, int c2) {

This method is used to put at least one digit. This means that the caller has 
to remember to add a '0' explicitly, which is questionable.
I suggest removing this method and invoke the correct combination of `putChar` 
and `putDigit` for more readable code.

src/java.base/share/classes/jdk/internal/math/ToDecimal.java line 165:

> 163:     }
> 164: 
> 165:     int length(byte[] str) {

Suggestion:

    final int length(byte[] str) {

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652975219
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652975321
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652972922
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652978056
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652984938
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652987069
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652991581
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652933181
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652993152
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652993281
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652993363
PR Review Comment: https://git.openjdk.org/jdk/pull/19730#discussion_r1652993591

Reply via email to