From 98bdd15b5716f857e0ce49714d9c4edbccfc83fd Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Thu, 29 Jun 2023 01:05:23 +0800 Subject: [PATCH 01/20] 8310929: Optimization for Integer.toString --- .../share/classes/java/lang/Integer.java | 161 +++++++++++++++++- 1 file changed, 155 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 8c8bcb9226f4d..828af00a5dbee 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -27,6 +27,7 @@ import jdk.internal.misc.CDS; import jdk.internal.misc.VM; +import jdk.internal.util.ByteArray; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -453,16 +454,104 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l */ @IntrinsicCandidate public static String toString(int i) { - int size = stringSize(i); - if (COMPACT_STRINGS) { - byte[] buf = new byte[size]; - getChars(i, size, buf); - return new String(buf, LATIN1); - } else { + if (!COMPACT_STRINGS) { + int size = stringSize(i); byte[] buf = new byte[size * 2]; StringUTF16.getChars(i, size, buf); return new String(buf, UTF16); } + + if (i == Integer.MIN_VALUE) { + return "-2147483648"; + } + + boolean negative = i < 0; + if (negative) { + i = -i; + } + final int[] digits = DecimalDigits.DIGITS; + + int off = 0; + final int q1 = i / 1000; + + byte[] buf; + if (q1 == 0) { + int v = digits[i]; + final int start = v >> 24; + buf = new byte[(negative ? 4 : 3) - start]; + if (negative) { + buf[0] = '-'; + off = 1; + } + + if (start == 0) { + buf[off] = (byte) (v >> 16); + ByteArray.setShort(buf, off + 1, (short) v); + } else if (start == 1) { + ByteArray.setShort(buf, off, (short) v); + } else { + buf[off] = (byte) v; + } + } else { + final int r1 = i - q1 * 1000; + final int q2 = q1 / 1000; + final int v1 = digits[r1]; + if (q2 == 0) { + final int v2 = digits[q1]; + int start = v2 >> 24; + + buf = new byte[(negative ? 7 : 6) - start]; + if (negative) { + buf[0] = '-'; + off = 1; + } + + if (start == 0) { + ByteArray.setShort(buf, off, (short) (v2 >> 8)); + off += 2; + } else if (start == 1) { + buf[off++] = (byte) (v2 >> 8); + } + ByteArray.setInt(buf, off, v2 << 24 | (v1 & 0xffffff)); + } else { + final int r2 = q1 - q2 * 1000; + final int q3 = q2 / 1000; + final int v2 = digits[r2]; + if (q3 == 0) { + int v = digits[q2]; + final int start = v >> 24; + + buf = new byte[(negative ? 10 : 9) - start]; + if (negative) { + buf[0] = '-'; + off = 1; + } + + if (start == 0) { + buf[off] = (byte) (v >> 16); + ByteArray.setShort(buf, off + 1, (short) v); + off += 3; + } else if (start == 1) { + ByteArray.setShort(buf, off, (short) v); + off += 2; + } else { + buf[off++] = (byte) v; + } + } else { + buf = new byte[negative ? 11 : 10]; + if (negative) { + buf[0] = '-'; + off = 1; + } + ByteArray.setInt(buf, off, ((q3 + '0') << 24) | (digits[q2 - q3 * 1000] & 0xffffff)); + off += 4; + } + + ByteArray.setShort(buf, off, (short) (v2 >> 8)); + ByteArray.setInt(buf, off + 2, (v2 << 24) | (v1 & 0xffffff)); + } + } + return new String(buf, LATIN1); } /** @@ -1051,6 +1140,66 @@ private static final class IntegerCache { private IntegerCache() {} } + /** + * cache array for 0-999 digits + */ + static final class DecimalDigits { + /** + * Use the four bytes of int to represent one blank_size byte and three ascii bytes. The four bytes are: + *
+         *     blank_size, c0, c1, c2
+         * 
+ * The logic for calculating blank_size is + *
+         *     blank_size = value < 10 ? 2 : (value < 100 ? 1 : 0)
+         * 
+ * The 1000 elements are as follows : + *
+         *       0 -> 2 0 0 0 -> (2 << 24) | ('0' << 16) | ('0' << 8) | '0' -> 0x2303030
+         *       1 -> 2 0 0 1 -> (2 << 24) | ('0' << 16) | ('0' << 8) | '1' -> 0x2303031
+         *       2 -> 2 0 0 2 -> (2 << 24) | ('0' << 16) | ('0' << 8) | '2' -> 0x2303032
+         *
+         *     ...
+         *
+         *      10 -> 1 0 1 0 -> (1 << 24) | ('0' << 16) | ('1' << 8) | '0' -> 0x1303130
+         *      11 -> 1 0 1 1 -> (1 << 24) | ('0' << 16) | ('1' << 8) | '1' -> 0x1303131
+         *      12 -> 1 0 1 2 -> (1 << 24) | ('0' << 16) | ('1' << 8) | '2' -> 0x1303132
+         *
+         *     ...
+         *
+         *     100 -> 0 1 0 0 -> (0 << 24) | ('1' << 16) | ('0' << 8) | '0' -> 0x313030
+         *     101 -> 0 1 0 1 -> (0 << 24) | ('1' << 16) | ('0' << 8) | '1' -> 0x313031
+         *     102 -> 0 1 0 2 -> (0 << 24) | ('1' << 16) | ('0' << 8) | '2' -> 0x313032
+         *
+         *     ...
+         *
+         *     997 -> 0 9 9 7 -> (0 << 24) | ('9' << 16) | ('9' << 8) | '7' -> 0x393937
+         *     998 -> 0 9 9 8 -> (0 << 24) | ('9' << 16) | ('9' << 8) | '8' -> 0x393938
+         *     999 -> 0 9 9 9 -> (0 << 24) | ('9' << 16) | ('9' << 8) | '9' -> 0x393939
+         * 
+ */ + @Stable + static final int[] DIGITS; + + static { + int[] digits = new int[1000]; + for (int i = 0; i < 10; i++) { + int i100 = i * 100; + for (int j = 0; j < 10; j++) { + int j10 = j * 10; + for (int k = 0; k < 10; k++) { + digits[i100 + j10 + k] + = ((i == 0 && j == 0) ? 2 : (i == 0) ? 1 : 0) << 24 + | ((i + '0') << 16) + | ((j + '0') << 8) + | (k + '0'); + } + } + } + DIGITS = digits; + } + } + /** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not From f0dab02842de7fb3dca177e588ac0ef98922bae3 Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Thu, 29 Jun 2023 06:12:56 +0800 Subject: [PATCH 02/20] postpone the division --- src/java.base/share/classes/java/lang/Integer.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 828af00a5dbee..13f0f1b3f78f1 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -470,12 +470,9 @@ public static String toString(int i) { i = -i; } final int[] digits = DecimalDigits.DIGITS; - int off = 0; - final int q1 = i / 1000; - byte[] buf; - if (q1 == 0) { + if (i < 1000) { int v = digits[i]; final int start = v >> 24; buf = new byte[(negative ? 4 : 3) - start]; @@ -493,10 +490,10 @@ public static String toString(int i) { buf[off] = (byte) v; } } else { + final int q1 = i / 1000; final int r1 = i - q1 * 1000; - final int q2 = q1 / 1000; final int v1 = digits[r1]; - if (q2 == 0) { + if (i < 1000000) { final int v2 = digits[q1]; int start = v2 >> 24; @@ -514,6 +511,7 @@ public static String toString(int i) { } ByteArray.setInt(buf, off, v2 << 24 | (v1 & 0xffffff)); } else { + final int q2 = q1 / 1000; final int r2 = q1 - q2 * 1000; final int q3 = q2 / 1000; final int v2 = digits[r2]; From ac650f7ba03f6277866f580c842a6cd1a8a68098 Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Fri, 30 Jun 2023 08:58:16 +0800 Subject: [PATCH 03/20] improve based on getChars --- .../share/classes/java/lang/Integer.java | 197 ++++-------------- 1 file changed, 42 insertions(+), 155 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 13f0f1b3f78f1..b9146278c1784 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -27,7 +27,7 @@ import jdk.internal.misc.CDS; import jdk.internal.misc.VM; -import jdk.internal.util.ByteArray; +import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -441,6 +441,39 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', } ; + /** + * Each element of the array represents the packaging of two ascii characters based on little endian:

+ *

+     *       0 -> '0' | ('0' << 8) -> 0x3030
+     *       1 -> '1' | ('0' << 8) -> 0x3130
+     *       2 -> '2' | ('0' << 8) -> 0x3230
+     *
+     *     ...
+     *
+     *      10 -> '0' | ('1' << 8)-> 0x3031
+     *      11 -> '1' | ('1' << 8)-> 0x3131
+     *      12 -> '2' | ('1' << 8)-> 0x3231
+     *
+     *     ...
+     *
+     *      97 -> '7' | ('9' << 8) -> 0x3739
+     *      98 -> '8' | ('9' << 8) -> 0x3839
+     *      99 -> '9' | ('9' << 8) -> 0x3939
+     * 
+ */ + @Stable + static final short[] DigitPacks = new short[] { + 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, + 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, + 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, + 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, + 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, + 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, + 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, + 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, + 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, + 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939 + }; /** * Returns a {@code String} object representing the @@ -454,102 +487,16 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l */ @IntrinsicCandidate public static String toString(int i) { - if (!COMPACT_STRINGS) { - int size = stringSize(i); + int size = stringSize(i); + if (COMPACT_STRINGS) { + byte[] buf = new byte[size]; + getChars(i, size, buf); + return new String(buf, LATIN1); + } else { byte[] buf = new byte[size * 2]; StringUTF16.getChars(i, size, buf); return new String(buf, UTF16); } - - if (i == Integer.MIN_VALUE) { - return "-2147483648"; - } - - boolean negative = i < 0; - if (negative) { - i = -i; - } - final int[] digits = DecimalDigits.DIGITS; - int off = 0; - byte[] buf; - if (i < 1000) { - int v = digits[i]; - final int start = v >> 24; - buf = new byte[(negative ? 4 : 3) - start]; - if (negative) { - buf[0] = '-'; - off = 1; - } - - if (start == 0) { - buf[off] = (byte) (v >> 16); - ByteArray.setShort(buf, off + 1, (short) v); - } else if (start == 1) { - ByteArray.setShort(buf, off, (short) v); - } else { - buf[off] = (byte) v; - } - } else { - final int q1 = i / 1000; - final int r1 = i - q1 * 1000; - final int v1 = digits[r1]; - if (i < 1000000) { - final int v2 = digits[q1]; - int start = v2 >> 24; - - buf = new byte[(negative ? 7 : 6) - start]; - if (negative) { - buf[0] = '-'; - off = 1; - } - - if (start == 0) { - ByteArray.setShort(buf, off, (short) (v2 >> 8)); - off += 2; - } else if (start == 1) { - buf[off++] = (byte) (v2 >> 8); - } - ByteArray.setInt(buf, off, v2 << 24 | (v1 & 0xffffff)); - } else { - final int q2 = q1 / 1000; - final int r2 = q1 - q2 * 1000; - final int q3 = q2 / 1000; - final int v2 = digits[r2]; - if (q3 == 0) { - int v = digits[q2]; - final int start = v >> 24; - - buf = new byte[(negative ? 10 : 9) - start]; - if (negative) { - buf[0] = '-'; - off = 1; - } - - if (start == 0) { - buf[off] = (byte) (v >> 16); - ByteArray.setShort(buf, off + 1, (short) v); - off += 3; - } else if (start == 1) { - ByteArray.setShort(buf, off, (short) v); - off += 2; - } else { - buf[off++] = (byte) v; - } - } else { - buf = new byte[negative ? 11 : 10]; - if (negative) { - buf[0] = '-'; - off = 1; - } - ByteArray.setInt(buf, off, ((q3 + '0') << 24) | (digits[q2 - q3 * 1000] & 0xffffff)); - off += 4; - } - - ByteArray.setShort(buf, off, (short) (v2 >> 8)); - ByteArray.setInt(buf, off + 2, (v2 << 24) | (v1 & 0xffffff)); - } - } - return new String(buf, LATIN1); } /** @@ -601,8 +548,8 @@ static int getChars(int i, int index, byte[] buf) { q = i / 100; r = (q * 100) - i; i = q; - buf[--charPos] = DigitOnes[r]; - buf[--charPos] = DigitTens[r]; + charPos -= 2; + Unsafe.getUnsafe().putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r]); } // We know there are at most two digits left at this point. @@ -1138,66 +1085,6 @@ private static final class IntegerCache { private IntegerCache() {} } - /** - * cache array for 0-999 digits - */ - static final class DecimalDigits { - /** - * Use the four bytes of int to represent one blank_size byte and three ascii bytes. The four bytes are: - *
-         *     blank_size, c0, c1, c2
-         * 
- * The logic for calculating blank_size is - *
-         *     blank_size = value < 10 ? 2 : (value < 100 ? 1 : 0)
-         * 
- * The 1000 elements are as follows : - *
-         *       0 -> 2 0 0 0 -> (2 << 24) | ('0' << 16) | ('0' << 8) | '0' -> 0x2303030
-         *       1 -> 2 0 0 1 -> (2 << 24) | ('0' << 16) | ('0' << 8) | '1' -> 0x2303031
-         *       2 -> 2 0 0 2 -> (2 << 24) | ('0' << 16) | ('0' << 8) | '2' -> 0x2303032
-         *
-         *     ...
-         *
-         *      10 -> 1 0 1 0 -> (1 << 24) | ('0' << 16) | ('1' << 8) | '0' -> 0x1303130
-         *      11 -> 1 0 1 1 -> (1 << 24) | ('0' << 16) | ('1' << 8) | '1' -> 0x1303131
-         *      12 -> 1 0 1 2 -> (1 << 24) | ('0' << 16) | ('1' << 8) | '2' -> 0x1303132
-         *
-         *     ...
-         *
-         *     100 -> 0 1 0 0 -> (0 << 24) | ('1' << 16) | ('0' << 8) | '0' -> 0x313030
-         *     101 -> 0 1 0 1 -> (0 << 24) | ('1' << 16) | ('0' << 8) | '1' -> 0x313031
-         *     102 -> 0 1 0 2 -> (0 << 24) | ('1' << 16) | ('0' << 8) | '2' -> 0x313032
-         *
-         *     ...
-         *
-         *     997 -> 0 9 9 7 -> (0 << 24) | ('9' << 16) | ('9' << 8) | '7' -> 0x393937
-         *     998 -> 0 9 9 8 -> (0 << 24) | ('9' << 16) | ('9' << 8) | '8' -> 0x393938
-         *     999 -> 0 9 9 9 -> (0 << 24) | ('9' << 16) | ('9' << 8) | '9' -> 0x393939
-         * 
- */ - @Stable - static final int[] DIGITS; - - static { - int[] digits = new int[1000]; - for (int i = 0; i < 10; i++) { - int i100 = i * 100; - for (int j = 0; j < 10; j++) { - int j10 = j * 10; - for (int k = 0; k < 10; k++) { - digits[i100 + j10 + k] - = ((i == 0 && j == 0) ? 2 : (i == 0) ? 1 : 0) << 24 - | ((i + '0') << 16) - | ((j + '0') << 8) - | (k + '0'); - } - } - } - DIGITS = digits; - } - } - /** * Returns an {@code Integer} instance representing the specified * {@code int} value. If a new {@code Integer} instance is not From cce5a1a3c1a095fdee5ca880b0f19d9dd145ee7a Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Fri, 30 Jun 2023 12:51:35 +0800 Subject: [PATCH 04/20] explicitly specify the endianness --- src/java.base/share/classes/java/lang/Integer.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index b9146278c1784..cb659a506ac87 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -543,19 +543,23 @@ static int getChars(int i, int index, byte[] buf) { i = -i; } + Unsafe unsafe = Unsafe.getUnsafe(); + // Generate two digits per iteration while (i <= -100) { q = i / 100; r = (q * 100) - i; i = q; charPos -= 2; - Unsafe.getUnsafe().putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r]); + unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r], false); } // We know there are at most two digits left at this point. - buf[--charPos] = DigitOnes[-i]; if (i < -9) { - buf[--charPos] = DigitTens[-i]; + charPos -= 2; + unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[-i], false); + } else { + buf[--charPos] = DigitOnes[-i]; } if (negative) { From 827213e295dab444962dd8978fcec00afb694405 Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Fri, 30 Jun 2023 14:21:22 +0800 Subject: [PATCH 05/20] optimization for : Integer#toString Long#toString StringBuilder#append(int) --- .../share/classes/java/lang/Integer.java | 40 ++-------- .../share/classes/java/lang/Long.java | 17 +++-- .../share/classes/java/lang/StringUTF16.java | 75 ++++++++++++++++--- 3 files changed, 82 insertions(+), 50 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index cb659a506ac87..724db697f83a3 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -415,38 +415,12 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l } while (charPos > 0); } - static final byte[] DigitTens = { - '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', - '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', - '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', - '3', '3', '3', '3', '3', '3', '3', '3', '3', '3', - '4', '4', '4', '4', '4', '4', '4', '4', '4', '4', - '5', '5', '5', '5', '5', '5', '5', '5', '5', '5', - '6', '6', '6', '6', '6', '6', '6', '6', '6', '6', - '7', '7', '7', '7', '7', '7', '7', '7', '7', '7', - '8', '8', '8', '8', '8', '8', '8', '8', '8', '8', - '9', '9', '9', '9', '9', '9', '9', '9', '9', '9', - } ; - - static final byte[] DigitOnes = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - } ; - /** * Each element of the array represents the packaging of two ascii characters based on little endian:

*

-     *       0 -> '0' | ('0' << 8) -> 0x3030
-     *       1 -> '1' | ('0' << 8) -> 0x3130
-     *       2 -> '2' | ('0' << 8) -> 0x3230
+     *      00 -> '0' | ('0' << 8) -> 0x3030
+     *      01 -> '1' | ('0' << 8) -> 0x3130
+     *      02 -> '2' | ('0' << 8) -> 0x3230
      *
      *     ...
      *
@@ -543,23 +517,21 @@ static int getChars(int i, int index, byte[] buf) {
             i = -i;
         }
 
-        Unsafe unsafe = Unsafe.getUnsafe();
-
         // Generate two digits per iteration
         while (i <= -100) {
             q = i / 100;
             r = (q * 100) - i;
             i = q;
             charPos -= 2;
-            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r], false);
+            Unsafe.getUnsafe().putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r], false);
         }
 
         // We know there are at most two digits left at this point.
         if (i < -9) {
             charPos -= 2;
-            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[-i], false);
+            Unsafe.getUnsafe().putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[-i], false);
         } else {
-            buf[--charPos] = DigitOnes[-i];
+            buf[--charPos] = (byte) ('0' - i);
         }
 
         if (negative) {
diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java
index 813837020fb8e..d9c5eb16dd0f9 100644
--- a/src/java.base/share/classes/java/lang/Long.java
+++ b/src/java.base/share/classes/java/lang/Long.java
@@ -34,6 +34,7 @@
 import java.util.Optional;
 
 import jdk.internal.misc.CDS;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.vm.annotation.ForceInline;
 import jdk.internal.vm.annotation.IntrinsicCandidate;
 import jdk.internal.vm.annotation.Stable;
@@ -513,13 +514,15 @@ static int getChars(long i, int index, byte[] buf) {
             i = -i;
         }
 
+        Unsafe unsafe = Unsafe.getUnsafe();
+
         // Get 2 digits/iteration using longs until quotient fits into an int
         while (i <= Integer.MIN_VALUE) {
             q = i / 100;
             r = (int)((q * 100) - i);
             i = q;
-            buf[--charPos] = Integer.DigitOnes[r];
-            buf[--charPos] = Integer.DigitTens[r];
+            charPos -= 2;
+            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, Integer.DigitPacks[r], false);
         }
 
         // Get 2 digits/iteration using ints
@@ -529,14 +532,16 @@ static int getChars(long i, int index, byte[] buf) {
             q2 = i2 / 100;
             r  = (q2 * 100) - i2;
             i2 = q2;
-            buf[--charPos] = Integer.DigitOnes[r];
-            buf[--charPos] = Integer.DigitTens[r];
+            charPos -= 2;
+            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, Integer.DigitPacks[r], false);
         }
 
         // We know there are at most two digits left at this point.
-        buf[--charPos] = Integer.DigitOnes[-i2];
         if (i2 < -9) {
-            buf[--charPos] = Integer.DigitTens[-i2];
+            charPos -= 2;
+            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, Integer.DigitPacks[-i2], false);
+        } else {
+            buf[--charPos] = (byte) ('0' - i2);
         }
 
         if (negative) {
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
index 73d8586399097..dbe5da2abf1d5 100644
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -32,10 +32,12 @@
 import java.util.function.IntConsumer;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.util.ArraysSupport;
 import jdk.internal.vm.annotation.DontInline;
 import jdk.internal.vm.annotation.ForceInline;
 import jdk.internal.vm.annotation.IntrinsicCandidate;
+import jdk.internal.vm.annotation.Stable;
 
 import static java.lang.String.UTF16;
 import static java.lang.String.LATIN1;
@@ -1513,6 +1515,32 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount,
         }
     }
 
+    /**
+     * Integer.DigitPacks UTF16 version
+     */
+    @Stable
+    private static final int[] DigitPacksUTF16;
+    static {
+        int[] digits = new int[]{
+                0x300030, 0x310030, 0x320030, 0x330030, 0x340030, 0x350030, 0x360030, 0x370030, 0x380030, 0x390030,
+                0x300031, 0x310031, 0x320031, 0x330031, 0x340031, 0x350031, 0x360031, 0x370031, 0x380031, 0x390031,
+                0x300032, 0x310032, 0x320032, 0x330032, 0x340032, 0x350032, 0x360032, 0x370032, 0x380032, 0x390032,
+                0x300033, 0x310033, 0x320033, 0x330033, 0x340033, 0x350033, 0x360033, 0x370033, 0x380033, 0x390033,
+                0x300034, 0x310034, 0x320034, 0x330034, 0x340034, 0x350034, 0x360034, 0x370034, 0x380034, 0x390034,
+                0x300035, 0x310035, 0x320035, 0x330035, 0x340035, 0x350035, 0x360035, 0x370035, 0x380035, 0x390035,
+                0x300036, 0x310036, 0x320036, 0x330036, 0x340036, 0x350036, 0x360036, 0x370036, 0x380036, 0x390036,
+                0x300037, 0x310037, 0x320037, 0x330037, 0x340037, 0x350037, 0x360037, 0x370037, 0x380037, 0x390037,
+                0x300038, 0x310038, 0x320038, 0x330038, 0x340038, 0x350038, 0x360038, 0x370038, 0x380038, 0x390038,
+                0x300039, 0x310039, 0x320039, 0x330039, 0x340039, 0x350039, 0x360039, 0x370039, 0x380039, 0x390039
+        };
+        if (isBigEndian()) {
+            for (int i = 0; i < digits.length; i++) {
+                digits[i] = digits[i] << 8;
+            }
+        }
+        DigitPacksUTF16 = digits;
+    }
+
     static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
 
     // Used by trusted callers.  Assumes all necessary bounds checks have
@@ -1541,14 +1569,26 @@ static int getChars(int i, int index, byte[] buf) {
             q = i / 100;
             r = (q * 100) - i;
             i = q;
-            putChar(buf, --charPos, Integer.DigitOnes[r]);
-            putChar(buf, --charPos, Integer.DigitTens[r]);
+
+            charPos -= 2;
+            Unsafe.getUnsafe().putIntUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
+                    DigitPacksUTF16[r],
+                    false);
         }
 
         // We know there are at most two digits left at this point.
-        putChar(buf, --charPos, Integer.DigitOnes[-i]);
+
         if (i < -9) {
-            putChar(buf, --charPos, Integer.DigitTens[-i]);
+            charPos -= 2;
+            Unsafe.getUnsafe().putIntUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
+                    DigitPacksUTF16[-i],
+                    false);
+        } else {
+            putChar(buf, --charPos, '0' - i);
         }
 
         if (negative) {
@@ -1581,8 +1621,12 @@ static int getChars(long i, int index, byte[] buf) {
             q = i / 100;
             r = (int)((q * 100) - i);
             i = q;
-            putChar(buf, --charPos, Integer.DigitOnes[r]);
-            putChar(buf, --charPos, Integer.DigitTens[r]);
+            charPos -= 2;
+            Unsafe.getUnsafe().putIntUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
+                    DigitPacksUTF16[r],
+                    false);
         }
 
         // Get 2 digits/iteration using ints
@@ -1592,14 +1636,25 @@ static int getChars(long i, int index, byte[] buf) {
             q2 = i2 / 100;
             r  = (q2 * 100) - i2;
             i2 = q2;
-            putChar(buf, --charPos, Integer.DigitOnes[r]);
-            putChar(buf, --charPos, Integer.DigitTens[r]);
+            charPos -= 2;
+            Unsafe.getUnsafe().putIntUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
+                    DigitPacksUTF16[r],
+                    false);
         }
 
         // We know there are at most two digits left at this point.
-        putChar(buf, --charPos, Integer.DigitOnes[-i2]);
+
         if (i2 < -9) {
-            putChar(buf, --charPos, Integer.DigitTens[-i2]);
+            charPos -= 2;
+            Unsafe.getUnsafe().putIntUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
+                    DigitPacksUTF16[-i2],
+                    false);
+        } else {
+            putChar(buf, --charPos, '0' - i2);
         }
 
         if (negative) {

From f3048876e49d72d773b5628ee21a0cb9f9335dc8 Mon Sep 17 00:00:00 2001
From: "shaojin.wensj" 
Date: Fri, 30 Jun 2023 18:39:18 +0800
Subject: [PATCH 06/20] format code

---
 .../share/classes/java/lang/Long.java         | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java
index d9c5eb16dd0f9..7c6360a09b8a3 100644
--- a/src/java.base/share/classes/java/lang/Long.java
+++ b/src/java.base/share/classes/java/lang/Long.java
@@ -514,15 +514,17 @@ static int getChars(long i, int index, byte[] buf) {
             i = -i;
         }
 
-        Unsafe unsafe = Unsafe.getUnsafe();
-
         // Get 2 digits/iteration using longs until quotient fits into an int
         while (i <= Integer.MIN_VALUE) {
             q = i / 100;
             r = (int)((q * 100) - i);
             i = q;
             charPos -= 2;
-            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, Integer.DigitPacks[r], false);
+            Unsafe.getUnsafe().putShortUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
+                    Integer.DigitPacks[r],
+                    false);
         }
 
         // Get 2 digits/iteration using ints
@@ -533,13 +535,21 @@ static int getChars(long i, int index, byte[] buf) {
             r  = (q2 * 100) - i2;
             i2 = q2;
             charPos -= 2;
-            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, Integer.DigitPacks[r], false);
+            Unsafe.getUnsafe().putShortUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
+                    Integer.DigitPacks[r],
+                    false);
         }
 
         // We know there are at most two digits left at this point.
         if (i2 < -9) {
             charPos -= 2;
-            unsafe.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, Integer.DigitPacks[-i2], false);
+            Unsafe.getUnsafe().putShortUnaligned(
+                    buf,
+                    Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
+                    Integer.DigitPacks[-i2],
+                    false);
         } else {
             buf[--charPos] = (byte) ('0' - i2);
         }

From bf9059bfd4779d12b7ebd115d48e164f78864663 Mon Sep 17 00:00:00 2001
From: "shaojin.wensj" 
Date: Fri, 30 Jun 2023 19:09:44 +0800
Subject: [PATCH 07/20] format code & comment

---
 src/java.base/share/classes/java/lang/Integer.java     | 6 +++---
 src/java.base/share/classes/java/lang/StringUTF16.java | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java
index 724db697f83a3..e5e5a83c26a27 100644
--- a/src/java.base/share/classes/java/lang/Integer.java
+++ b/src/java.base/share/classes/java/lang/Integer.java
@@ -424,9 +424,9 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l
      *
      *     ...
      *
-     *      10 -> '0' | ('1' << 8)-> 0x3031
-     *      11 -> '1' | ('1' << 8)-> 0x3131
-     *      12 -> '2' | ('1' << 8)-> 0x3231
+     *      10 -> '0' | ('1' << 8) -> 0x3031
+     *      11 -> '1' | ('1' << 8) -> 0x3131
+     *      12 -> '2' | ('1' << 8) -> 0x3231
      *
      *     ...
      *
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
index dbe5da2abf1d5..69c1a67b2b5e5 100644
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -1535,7 +1535,7 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount,
         };
         if (isBigEndian()) {
             for (int i = 0; i < digits.length; i++) {
-                digits[i] = digits[i] << 8;
+                digits[i] <<= 8;
             }
         }
         DigitPacksUTF16 = digits;

From 8a1d1c0da152a79bb6390a3593671c81dda001aa Mon Sep 17 00:00:00 2001
From: "shaojin.wensj" 
Date: Fri, 30 Jun 2023 21:20:41 +0800
Subject: [PATCH 08/20] simplify code

---
 src/java.base/share/classes/java/lang/Long.java       | 11 ++++-------
 .../share/classes/java/lang/StringUTF16.java          | 11 ++++-------
 2 files changed, 8 insertions(+), 14 deletions(-)

diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java
index 7c6360a09b8a3..cc68d66e63863 100644
--- a/src/java.base/share/classes/java/lang/Long.java
+++ b/src/java.base/share/classes/java/lang/Long.java
@@ -506,7 +506,6 @@ public static String toUnsignedString(long i) {
      */
     static int getChars(long i, int index, byte[] buf) {
         long q;
-        int r;
         int charPos = index;
 
         boolean negative = (i < 0);
@@ -517,14 +516,13 @@ static int getChars(long i, int index, byte[] buf) {
         // Get 2 digits/iteration using longs until quotient fits into an int
         while (i <= Integer.MIN_VALUE) {
             q = i / 100;
-            r = (int)((q * 100) - i);
-            i = q;
             charPos -= 2;
             Unsafe.getUnsafe().putShortUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
-                    Integer.DigitPacks[r],
+                    Integer.DigitPacks[(int)((q * 100) - i)],
                     false);
+            i = q;
         }
 
         // Get 2 digits/iteration using ints
@@ -532,14 +530,13 @@ static int getChars(long i, int index, byte[] buf) {
         int i2 = (int)i;
         while (i2 <= -100) {
             q2 = i2 / 100;
-            r  = (q2 * 100) - i2;
-            i2 = q2;
             charPos -= 2;
             Unsafe.getUnsafe().putShortUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
-                    Integer.DigitPacks[r],
+                    Integer.DigitPacks[(q2 * 100) - i2],
                     false);
+            i2 = q2;
         }
 
         // We know there are at most two digits left at this point.
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
index 69c1a67b2b5e5..b2405f619b102 100644
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -1608,7 +1608,6 @@ static int getChars(int i, int index, byte[] buf) {
      */
     static int getChars(long i, int index, byte[] buf) {
         long q;
-        int r;
         int charPos = index;
 
         boolean negative = (i < 0);
@@ -1619,14 +1618,13 @@ static int getChars(long i, int index, byte[] buf) {
         // Get 2 digits/iteration using longs until quotient fits into an int
         while (i <= Integer.MIN_VALUE) {
             q = i / 100;
-            r = (int)((q * 100) - i);
-            i = q;
             charPos -= 2;
             Unsafe.getUnsafe().putIntUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
-                    DigitPacksUTF16[r],
+                    DigitPacksUTF16[(int)((q * 100) - i)],
                     false);
+            i = q;
         }
 
         // Get 2 digits/iteration using ints
@@ -1634,14 +1632,13 @@ static int getChars(long i, int index, byte[] buf) {
         int i2 = (int)i;
         while (i2 <= -100) {
             q2 = i2 / 100;
-            r  = (q2 * 100) - i2;
-            i2 = q2;
             charPos -= 2;
             Unsafe.getUnsafe().putIntUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
-                    DigitPacksUTF16[r],
+                    DigitPacksUTF16[(q2 * 100) - i2],
                     false);
+            i2 = q2;
         }
 
         // We know there are at most two digits left at this point.

From 34e7191434a12dd4a9c8afc288ec61f797d04a29 Mon Sep 17 00:00:00 2001
From: "shaojin.wensj" 
Date: Sat, 1 Jul 2023 06:52:42 +0800
Subject: [PATCH 09/20] code format

---
 src/java.base/share/classes/java/lang/Integer.java     | 2 +-
 src/java.base/share/classes/java/lang/Long.java        | 2 +-
 src/java.base/share/classes/java/lang/StringUTF16.java | 2 --
 3 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java
index e5e5a83c26a27..c9afec6ac4685 100644
--- a/src/java.base/share/classes/java/lang/Integer.java
+++ b/src/java.base/share/classes/java/lang/Integer.java
@@ -531,7 +531,7 @@ static int getChars(int i, int index, byte[] buf) {
             charPos -= 2;
             Unsafe.getUnsafe().putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[-i], false);
         } else {
-            buf[--charPos] = (byte) ('0' - i);
+            buf[--charPos] = (byte)('0' - i);
         }
 
         if (negative) {
diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java
index cc68d66e63863..8b739fd8dd329 100644
--- a/src/java.base/share/classes/java/lang/Long.java
+++ b/src/java.base/share/classes/java/lang/Long.java
@@ -548,7 +548,7 @@ static int getChars(long i, int index, byte[] buf) {
                     Integer.DigitPacks[-i2],
                     false);
         } else {
-            buf[--charPos] = (byte) ('0' - i2);
+            buf[--charPos] = (byte)('0' - i2);
         }
 
         if (negative) {
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
index b2405f619b102..6922768cdce60 100644
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -1579,7 +1579,6 @@ static int getChars(int i, int index, byte[] buf) {
         }
 
         // We know there are at most two digits left at this point.
-
         if (i < -9) {
             charPos -= 2;
             Unsafe.getUnsafe().putIntUnaligned(
@@ -1642,7 +1641,6 @@ static int getChars(long i, int index, byte[] buf) {
         }
 
         // We know there are at most two digits left at this point.
-
         if (i2 < -9) {
             charPos -= 2;
             Unsafe.getUnsafe().putIntUnaligned(

From d07fde67e7f14e4238f04258af468d69dc7464c0 Mon Sep 17 00:00:00 2001
From: "shaojin.wensj" 
Date: Sat, 1 Jul 2023 18:14:29 +0800
Subject: [PATCH 10/20] private static final Unsafe

---
 src/java.base/share/classes/java/lang/Integer.java   |  6 ++++--
 src/java.base/share/classes/java/lang/Long.java      |  8 +++++---
 .../share/classes/java/lang/StringUTF16.java         | 12 +++++++-----
 3 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java
index c9afec6ac4685..85748d64497df 100644
--- a/src/java.base/share/classes/java/lang/Integer.java
+++ b/src/java.base/share/classes/java/lang/Integer.java
@@ -74,6 +74,8 @@
 @jdk.internal.ValueBased
 public final class Integer extends Number
         implements Comparable, Constable, ConstantDesc {
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
     /**
      * A constant holding the minimum value an {@code int} can
      * have, -231.
@@ -523,13 +525,13 @@ static int getChars(int i, int index, byte[] buf) {
             r = (q * 100) - i;
             i = q;
             charPos -= 2;
-            Unsafe.getUnsafe().putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r], false);
+            UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r], false);
         }
 
         // We know there are at most two digits left at this point.
         if (i < -9) {
             charPos -= 2;
-            Unsafe.getUnsafe().putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[-i], false);
+            UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[-i], false);
         } else {
             buf[--charPos] = (byte)('0' - i);
         }
diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java
index 8b739fd8dd329..42fa2ae0fbbb9 100644
--- a/src/java.base/share/classes/java/lang/Long.java
+++ b/src/java.base/share/classes/java/lang/Long.java
@@ -74,6 +74,8 @@
 @jdk.internal.ValueBased
 public final class Long extends Number
         implements Comparable, Constable, ConstantDesc {
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
     /**
      * A constant holding the minimum value a {@code long} can
      * have, -263.
@@ -517,7 +519,7 @@ static int getChars(long i, int index, byte[] buf) {
         while (i <= Integer.MIN_VALUE) {
             q = i / 100;
             charPos -= 2;
-            Unsafe.getUnsafe().putShortUnaligned(
+            UNSAFE.putShortUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
                     Integer.DigitPacks[(int)((q * 100) - i)],
@@ -531,7 +533,7 @@ static int getChars(long i, int index, byte[] buf) {
         while (i2 <= -100) {
             q2 = i2 / 100;
             charPos -= 2;
-            Unsafe.getUnsafe().putShortUnaligned(
+            UNSAFE.putShortUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
                     Integer.DigitPacks[(q2 * 100) - i2],
@@ -542,7 +544,7 @@ static int getChars(long i, int index, byte[] buf) {
         // We know there are at most two digits left at this point.
         if (i2 < -9) {
             charPos -= 2;
-            Unsafe.getUnsafe().putShortUnaligned(
+            UNSAFE.putShortUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos,
                     Integer.DigitPacks[-i2],
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
index 6922768cdce60..c6f7815ade7d6 100644
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -1515,6 +1515,8 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount,
         }
     }
 
+    private static final Unsafe UNSAFE = Unsafe.getUnsafe();
+
     /**
      * Integer.DigitPacks UTF16 version
      */
@@ -1571,7 +1573,7 @@ static int getChars(int i, int index, byte[] buf) {
             i = q;
 
             charPos -= 2;
-            Unsafe.getUnsafe().putIntUnaligned(
+            UNSAFE.putIntUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
                     DigitPacksUTF16[r],
@@ -1581,7 +1583,7 @@ static int getChars(int i, int index, byte[] buf) {
         // We know there are at most two digits left at this point.
         if (i < -9) {
             charPos -= 2;
-            Unsafe.getUnsafe().putIntUnaligned(
+            UNSAFE.putIntUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
                     DigitPacksUTF16[-i],
@@ -1618,7 +1620,7 @@ static int getChars(long i, int index, byte[] buf) {
         while (i <= Integer.MIN_VALUE) {
             q = i / 100;
             charPos -= 2;
-            Unsafe.getUnsafe().putIntUnaligned(
+            UNSAFE.putIntUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
                     DigitPacksUTF16[(int)((q * 100) - i)],
@@ -1632,7 +1634,7 @@ static int getChars(long i, int index, byte[] buf) {
         while (i2 <= -100) {
             q2 = i2 / 100;
             charPos -= 2;
-            Unsafe.getUnsafe().putIntUnaligned(
+            UNSAFE.putIntUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
                     DigitPacksUTF16[(q2 * 100) - i2],
@@ -1643,7 +1645,7 @@ static int getChars(long i, int index, byte[] buf) {
         // We know there are at most two digits left at this point.
         if (i2 < -9) {
             charPos -= 2;
-            Unsafe.getUnsafe().putIntUnaligned(
+            UNSAFE.putIntUnaligned(
                     buf,
                     Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1),
                     DigitPacksUTF16[-i2],

From 8663f3d5c5c148377dfc73920256e60c4f4074af Mon Sep 17 00:00:00 2001
From: "shaojin.wensj" 
Date: Sat, 1 Jul 2023 22:06:18 +0800
Subject: [PATCH 11/20] use upper case for static final field

---
 .../share/classes/java/lang/Integer.java         |  6 +++---
 src/java.base/share/classes/java/lang/Long.java  |  6 +++---
 .../share/classes/java/lang/StringUTF16.java     | 16 ++++++++--------
 3 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java
index 85748d64497df..85f860c41abce 100644
--- a/src/java.base/share/classes/java/lang/Integer.java
+++ b/src/java.base/share/classes/java/lang/Integer.java
@@ -438,7 +438,7 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l
      * 
*/ @Stable - static final short[] DigitPacks = new short[] { + static final short[] PACKED_DIGITS = new short[] { 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, @@ -525,13 +525,13 @@ static int getChars(int i, int index, byte[] buf) { r = (q * 100) - i; i = q; charPos -= 2; - UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[r], false); + UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[r], false); } // We know there are at most two digits left at this point. if (i < -9) { charPos -= 2; - UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, DigitPacks[-i], false); + UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[-i], false); } else { buf[--charPos] = (byte)('0' - i); } diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 42fa2ae0fbbb9..9a36bc593651f 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -522,7 +522,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putShortUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - Integer.DigitPacks[(int)((q * 100) - i)], + Integer.PACKED_DIGITS[(int)((q * 100) - i)], false); i = q; } @@ -536,7 +536,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putShortUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - Integer.DigitPacks[(q2 * 100) - i2], + Integer.PACKED_DIGITS[(q2 * 100) - i2], false); i2 = q2; } @@ -547,7 +547,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putShortUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - Integer.DigitPacks[-i2], + Integer.PACKED_DIGITS[-i2], false); } else { buf[--charPos] = (byte)('0' - i2); diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index c6f7815ade7d6..301bcf6673944 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1518,10 +1518,10 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, private static final Unsafe UNSAFE = Unsafe.getUnsafe(); /** - * Integer.DigitPacks UTF16 version + * Integer.PACKED_DIGITS UTF16 version */ @Stable - private static final int[] DigitPacksUTF16; + private static final int[] PACKED_DIGITS_UTF16; static { int[] digits = new int[]{ 0x300030, 0x310030, 0x320030, 0x330030, 0x340030, 0x350030, 0x360030, 0x370030, 0x380030, 0x390030, @@ -1540,7 +1540,7 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, digits[i] <<= 8; } } - DigitPacksUTF16 = digits; + PACKED_DIGITS_UTF16 = digits; } static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; @@ -1576,7 +1576,7 @@ static int getChars(int i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - DigitPacksUTF16[r], + PACKED_DIGITS_UTF16[r], false); } @@ -1586,7 +1586,7 @@ static int getChars(int i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - DigitPacksUTF16[-i], + PACKED_DIGITS_UTF16[-i], false); } else { putChar(buf, --charPos, '0' - i); @@ -1623,7 +1623,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - DigitPacksUTF16[(int)((q * 100) - i)], + PACKED_DIGITS_UTF16[(int)((q * 100) - i)], false); i = q; } @@ -1637,7 +1637,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - DigitPacksUTF16[(q2 * 100) - i2], + PACKED_DIGITS_UTF16[(q2 * 100) - i2], false); i2 = q2; } @@ -1648,7 +1648,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - DigitPacksUTF16[-i2], + PACKED_DIGITS_UTF16[-i2], false); } else { putChar(buf, --charPos, '0' - i2); From 9a8cf2acb0409136d15c7c6d6f12e9d16846efec Mon Sep 17 00:00:00 2001 From: liach <7806504+liach@users.noreply.github.com> Date: Sun, 2 Jul 2023 11:50:34 +0800 Subject: [PATCH 12/20] Adapt endian in pack Co-authored-by: liach --- .../share/classes/java/lang/StringUTF16.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 301bcf6673944..c198e66e4c88f 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1518,12 +1518,17 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, private static final Unsafe UNSAFE = Unsafe.getUnsafe(); /** - * Integer.PACKED_DIGITS UTF16 version + * UTF16 version of {@link Integer#PACKED_DIGITS}, but the endianness + * of each integer is already adapted to platform. + * As a result, the packed values should NOT be recombined + * with bitwise operations, like {@code p[a] << 32 | p[b]}, and can only be + * passed to {@link Unsafe#putIntUnaligned(Object, long, int)} without a + * boolean parameter. */ @Stable private static final int[] PACKED_DIGITS_UTF16; static { - int[] digits = new int[]{ + int[] digits = new int[] { 0x300030, 0x310030, 0x320030, 0x330030, 0x340030, 0x350030, 0x360030, 0x370030, 0x380030, 0x390030, 0x300031, 0x310031, 0x320031, 0x330031, 0x340031, 0x350031, 0x360031, 0x370031, 0x380031, 0x390031, 0x300032, 0x310032, 0x320032, 0x330032, 0x340032, 0x350032, 0x360032, 0x370032, 0x380032, 0x390032, @@ -1537,7 +1542,7 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, }; if (isBigEndian()) { for (int i = 0; i < digits.length; i++) { - digits[i] <<= 8; + digits[i] = Integer.reverseBytes(digits[i] << 8); } } PACKED_DIGITS_UTF16 = digits; @@ -1576,8 +1581,7 @@ static int getChars(int i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[r], - false); + PACKED_DIGITS_UTF16[r]); } // We know there are at most two digits left at this point. @@ -1586,8 +1590,7 @@ static int getChars(int i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[-i], - false); + PACKED_DIGITS_UTF16[-i]); } else { putChar(buf, --charPos, '0' - i); } @@ -1623,8 +1626,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[(int)((q * 100) - i)], - false); + PACKED_DIGITS_UTF16[(int)((q * 100) - i)]); i = q; } @@ -1637,8 +1639,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[(q2 * 100) - i2], - false); + PACKED_DIGITS_UTF16[(q2 * 100) - i2]); i2 = q2; } @@ -1648,8 +1649,7 @@ static int getChars(long i, int index, byte[] buf) { UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[-i2], - false); + PACKED_DIGITS_UTF16[-i2]); } else { putChar(buf, --charPos, '0' - i2); } From 75abb0ebb1dc958d6ae8138e38ff23d638eb58f6 Mon Sep 17 00:00:00 2001 From: liach <7806504+liach@users.noreply.github.com> Date: Mon, 3 Jul 2023 11:44:11 +0800 Subject: [PATCH 13/20] Integer/Long toString test against compact strings Co-authored-by: liach --- test/jdk/java/lang/Integer/ToString.java | 20 ++++++++++++-------- test/jdk/java/lang/Long/ToString.java | 20 ++++++++++++-------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/test/jdk/java/lang/Integer/ToString.java b/test/jdk/java/lang/Integer/ToString.java index 060e0666eb928..0ada8bbf47ca0 100644 --- a/test/jdk/java/lang/Integer/ToString.java +++ b/test/jdk/java/lang/Integer/ToString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,20 @@ /* * @test - * @bug 8136500 - * @summary Test Integer.toString method + * @bug 8136500 8310929 + * @summary Test Integer.toString method for both compact and non-compact strings + * @run junit/othervm -XX:+CompactStrings ToString + * @run junit/othervm -XX:-CompactStrings ToString */ +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ToString { - public static void main(String[] args) throws Exception { + @Test + public void testBase10() { test("-2147483648", Integer.MIN_VALUE); test("2147483647", Integer.MAX_VALUE); test("0", 0); @@ -77,9 +84,6 @@ private static void buildAndTest(int c) { } private static void test(String expected, int value) { - String actual = Integer.toString(value); - if (!expected.equals(actual)) { - throw new RuntimeException("Expected " + expected + ", but got " + actual); - } + assertEquals(expected, Integer.toString(value)); } } diff --git a/test/jdk/java/lang/Long/ToString.java b/test/jdk/java/lang/Long/ToString.java index a420e3ed25e05..4dd457da2fd8e 100644 --- a/test/jdk/java/lang/Long/ToString.java +++ b/test/jdk/java/lang/Long/ToString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,13 +23,20 @@ /* * @test - * @bug 8136500 - * @summary Test Long.toString method + * @bug 8136500 8310929 + * @summary Test Long.toString method for both compact and non-compact strings + * @run junit/othervm -XX:+CompactStrings ToString + * @run junit/othervm -XX:-CompactStrings ToString */ +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + public class ToString { - public static void main(String[] args) throws Exception { + @Test + public void testBase10() { test("-9223372036854775808", Long.MIN_VALUE); test("9223372036854775807", Long.MAX_VALUE); test("0", 0); @@ -77,9 +84,6 @@ private static void buildAndTest(long c) { } private static void test(String expected, long value) { - String actual = Long.toString(value); - if (!expected.equals(actual)) { - throw new RuntimeException("Expected " + expected + ", but got " + actual); - } + assertEquals(expected, Long.toString(value)); } } From 6eb9150cc93d975663e96b637bd3457ed474f7fe Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Tue, 18 Jul 2023 09:42:50 +0800 Subject: [PATCH 14/20] assert bounds check --- src/java.base/share/classes/java/lang/Integer.java | 2 ++ src/java.base/share/classes/java/lang/Long.java | 3 +++ src/java.base/share/classes/java/lang/StringUTF16.java | 5 +++++ 3 files changed, 10 insertions(+) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 85f860c41abce..f94bcc6c44cd5 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -525,12 +525,14 @@ static int getChars(int i, int index, byte[] buf) { r = (q * 100) - i; i = q; charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[r], false); } // We know there are at most two digits left at this point. if (i < -9) { charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[-i], false); } else { buf[--charPos] = (byte)('0' - i); diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 9a36bc593651f..3349361eb9ada 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -519,6 +519,7 @@ static int getChars(long i, int index, byte[] buf) { while (i <= Integer.MIN_VALUE) { q = i / 100; charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putShortUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, @@ -533,6 +534,7 @@ static int getChars(long i, int index, byte[] buf) { while (i2 <= -100) { q2 = i2 / 100; charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putShortUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, @@ -544,6 +546,7 @@ static int getChars(long i, int index, byte[] buf) { // We know there are at most two digits left at this point. if (i2 < -9) { charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putShortUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index c198e66e4c88f..f61499d3d1f19 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1578,6 +1578,7 @@ static int getChars(int i, int index, byte[] buf) { i = q; charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), @@ -1587,6 +1588,7 @@ static int getChars(int i, int index, byte[] buf) { // We know there are at most two digits left at this point. if (i < -9) { charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), @@ -1623,6 +1625,7 @@ static int getChars(long i, int index, byte[] buf) { while (i <= Integer.MIN_VALUE) { q = i / 100; charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), @@ -1636,6 +1639,7 @@ static int getChars(long i, int index, byte[] buf) { while (i2 <= -100) { q2 = i2 / 100; charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), @@ -1646,6 +1650,7 @@ static int getChars(long i, int index, byte[] buf) { // We know there are at most two digits left at this point. if (i2 < -9) { charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), From c2b1887f84b4c105743ac4c7e3604f76df83124f Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Fri, 1 Sep 2023 19:32:36 +0800 Subject: [PATCH 15/20] UTF16 & Latin1 use same lookup table --- .../share/classes/java/lang/StringUTF16.java | 64 ++++++++----------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index f61499d3d1f19..741aa79e00a16 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1517,37 +1517,6 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - /** - * UTF16 version of {@link Integer#PACKED_DIGITS}, but the endianness - * of each integer is already adapted to platform. - * As a result, the packed values should NOT be recombined - * with bitwise operations, like {@code p[a] << 32 | p[b]}, and can only be - * passed to {@link Unsafe#putIntUnaligned(Object, long, int)} without a - * boolean parameter. - */ - @Stable - private static final int[] PACKED_DIGITS_UTF16; - static { - int[] digits = new int[] { - 0x300030, 0x310030, 0x320030, 0x330030, 0x340030, 0x350030, 0x360030, 0x370030, 0x380030, 0x390030, - 0x300031, 0x310031, 0x320031, 0x330031, 0x340031, 0x350031, 0x360031, 0x370031, 0x380031, 0x390031, - 0x300032, 0x310032, 0x320032, 0x330032, 0x340032, 0x350032, 0x360032, 0x370032, 0x380032, 0x390032, - 0x300033, 0x310033, 0x320033, 0x330033, 0x340033, 0x350033, 0x360033, 0x370033, 0x380033, 0x390033, - 0x300034, 0x310034, 0x320034, 0x330034, 0x340034, 0x350034, 0x360034, 0x370034, 0x380034, 0x390034, - 0x300035, 0x310035, 0x320035, 0x330035, 0x340035, 0x350035, 0x360035, 0x370035, 0x380035, 0x390035, - 0x300036, 0x310036, 0x320036, 0x330036, 0x340036, 0x350036, 0x360036, 0x370036, 0x380036, 0x390036, - 0x300037, 0x310037, 0x320037, 0x330037, 0x340037, 0x350037, 0x360037, 0x370037, 0x380037, 0x390037, - 0x300038, 0x310038, 0x320038, 0x330038, 0x340038, 0x350038, 0x360038, 0x370038, 0x380038, 0x390038, - 0x300039, 0x310039, 0x320039, 0x330039, 0x340039, 0x350039, 0x360039, 0x370039, 0x380039, 0x390039 - }; - if (isBigEndian()) { - for (int i = 0; i < digits.length; i++) { - digits[i] = Integer.reverseBytes(digits[i] << 8); - } - } - PACKED_DIGITS_UTF16 = digits; - } - static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; // Used by trusted callers. Assumes all necessary bounds checks have @@ -1577,22 +1546,30 @@ static int getChars(int i, int index, byte[] buf) { r = (q * 100) - i; i = q; + int packed = (int) Integer.PACKED_DIGITS[r]; + int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); + charPos -= 2; assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[r]); + inflated, + false); } // We know there are at most two digits left at this point. if (i < -9) { + int packed = (int) Integer.PACKED_DIGITS[-i]; + int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); + charPos -= 2; assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[-i]); + inflated, + false); } else { putChar(buf, --charPos, '0' - i); } @@ -1624,12 +1601,17 @@ static int getChars(long i, int index, byte[] buf) { // Get 2 digits/iteration using longs until quotient fits into an int while (i <= Integer.MIN_VALUE) { q = i / 100; + + int packed = (int) Integer.PACKED_DIGITS[(int)((q * 100) - i)]; + int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); + charPos -= 2; assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[(int)((q * 100) - i)]); + inflated, + false); i = q; } @@ -1638,23 +1620,33 @@ static int getChars(long i, int index, byte[] buf) { int i2 = (int)i; while (i2 <= -100) { q2 = i2 / 100; + + int packed = (int) Integer.PACKED_DIGITS[(q2 * 100) - i2]; + int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); + charPos -= 2; assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[(q2 * 100) - i2]); + inflated, + false); i2 = q2; } // We know there are at most two digits left at this point. if (i2 < -9) { charPos -= 2; + + int packed = (int) Integer.PACKED_DIGITS[-i2]; + int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; UNSAFE.putIntUnaligned( buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - PACKED_DIGITS_UTF16[-i2]); + inflated, + false); } else { putChar(buf, --charPos, '0' - i2); } From 0d149fa9be62788346f6e9844f5045e692711e70 Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Fri, 1 Sep 2023 20:32:59 +0800 Subject: [PATCH 16/20] remove unused import --- src/java.base/share/classes/java/lang/StringUTF16.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 741aa79e00a16..c6faebd25044c 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -37,7 +37,6 @@ import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; -import jdk.internal.vm.annotation.Stable; import static java.lang.String.UTF16; import static java.lang.String.LATIN1; From ed1c58bb600a3b887d860a07e033cb0ba4ac3f1c Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Mon, 4 Sep 2023 23:44:59 +0800 Subject: [PATCH 17/20] move Integer/Long.getChars to StringLatin1 --- .../java/lang/AbstractStringBuilder.java | 4 +- .../share/classes/java/lang/Integer.java | 90 +--------- .../share/classes/java/lang/Long.java | 78 +-------- .../classes/java/lang/StringConcatHelper.java | 4 +- .../share/classes/java/lang/StringLatin1.java | 162 ++++++++++++++++++ .../share/classes/java/lang/StringUTF16.java | 14 +- 6 files changed, 175 insertions(+), 177 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index e58ded864f070..2be557dc4bc84 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -832,7 +832,7 @@ public AbstractStringBuilder append(int i) { int spaceNeeded = count + Integer.stringSize(i); ensureCapacityInternal(spaceNeeded); if (isLatin1()) { - Integer.getChars(i, spaceNeeded, value); + StringLatin1.getChars(i, spaceNeeded, value); } else { StringUTF16.getChars(i, count, spaceNeeded, value); } @@ -857,7 +857,7 @@ public AbstractStringBuilder append(long l) { int spaceNeeded = count + Long.stringSize(l); ensureCapacityInternal(spaceNeeded); if (isLatin1()) { - Long.getChars(l, spaceNeeded, value); + StringLatin1.getChars(l, spaceNeeded, value); } else { StringUTF16.getChars(l, count, spaceNeeded, value); } diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index f94bcc6c44cd5..2b2377a889bbe 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -27,7 +27,6 @@ import jdk.internal.misc.CDS; import jdk.internal.misc.VM; -import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -74,8 +73,6 @@ @jdk.internal.ValueBased public final class Integer extends Number implements Comparable, Constable, ConstantDesc { - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - /** * A constant holding the minimum value an {@code int} can * have, -231. @@ -417,40 +414,6 @@ private static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int l } while (charPos > 0); } - /** - * Each element of the array represents the packaging of two ascii characters based on little endian:

- *

-     *      00 -> '0' | ('0' << 8) -> 0x3030
-     *      01 -> '1' | ('0' << 8) -> 0x3130
-     *      02 -> '2' | ('0' << 8) -> 0x3230
-     *
-     *     ...
-     *
-     *      10 -> '0' | ('1' << 8) -> 0x3031
-     *      11 -> '1' | ('1' << 8) -> 0x3131
-     *      12 -> '2' | ('1' << 8) -> 0x3231
-     *
-     *     ...
-     *
-     *      97 -> '7' | ('9' << 8) -> 0x3739
-     *      98 -> '8' | ('9' << 8) -> 0x3839
-     *      99 -> '9' | ('9' << 8) -> 0x3939
-     * 
- */ - @Stable - static final short[] PACKED_DIGITS = new short[] { - 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, - 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, - 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, - 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, - 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, - 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, - 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, - 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, - 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, - 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939 - }; - /** * Returns a {@code String} object representing the * specified integer. The argument is converted to signed decimal @@ -466,7 +429,7 @@ public static String toString(int i) { int size = stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; - getChars(i, size, buf); + StringLatin1.getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; @@ -493,57 +456,6 @@ public static String toUnsignedString(int i) { return Long.toString(toUnsignedLong(i)); } - /** - * Places characters representing the integer i into the - * character array buf. The characters are placed into - * the buffer backwards starting with the least significant - * digit at the specified index (exclusive), and working - * backwards from there. - * - * @implNote This method converts positive inputs into negative - * values, to cover the Integer.MIN_VALUE case. Converting otherwise - * (negative to positive) will expose -Integer.MIN_VALUE that overflows - * integer. - * - * @param i value to convert - * @param index next index, after the least significant digit - * @param buf target buffer, Latin1-encoded - * @return index of the most significant digit or minus sign, if present - */ - static int getChars(int i, int index, byte[] buf) { - int q, r; - int charPos = index; - - boolean negative = i < 0; - if (!negative) { - i = -i; - } - - // Generate two digits per iteration - while (i <= -100) { - q = i / 100; - r = (q * 100) - i; - i = q; - charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[r], false); - } - - // We know there are at most two digits left at this point. - if (i < -9) { - charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[-i], false); - } else { - buf[--charPos] = (byte)('0' - i); - } - - if (negative) { - buf[--charPos] = (byte)'-'; - } - return charPos; - } - /** * Returns the string representation size for a given int value. * diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 3349361eb9ada..91583c26be106 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -34,7 +34,6 @@ import java.util.Optional; import jdk.internal.misc.CDS; -import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -74,8 +73,6 @@ @jdk.internal.ValueBased public final class Long extends Number implements Comparable, Constable, ConstantDesc { - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - /** * A constant holding the minimum value a {@code long} can * have, -263. @@ -462,7 +459,7 @@ public static String toString(long i) { int size = stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; - getChars(i, size, buf); + StringLatin1.getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; @@ -489,79 +486,6 @@ public static String toUnsignedString(long i) { return toUnsignedString(i, 10); } - /** - * Places characters representing the long i into the - * character array buf. The characters are placed into - * the buffer backwards starting with the least significant - * digit at the specified index (exclusive), and working - * backwards from there. - * - * @implNote This method converts positive inputs into negative - * values, to cover the Long.MIN_VALUE case. Converting otherwise - * (negative to positive) will expose -Long.MIN_VALUE that overflows - * long. - * - * @param i value to convert - * @param index next index, after the least significant digit - * @param buf target buffer, Latin1-encoded - * @return index of the most significant digit or minus sign, if present - */ - static int getChars(long i, int index, byte[] buf) { - long q; - int charPos = index; - - boolean negative = (i < 0); - if (!negative) { - i = -i; - } - - // Get 2 digits/iteration using longs until quotient fits into an int - while (i <= Integer.MIN_VALUE) { - q = i / 100; - charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - Integer.PACKED_DIGITS[(int)((q * 100) - i)], - false); - i = q; - } - - // Get 2 digits/iteration using ints - int q2; - int i2 = (int)i; - while (i2 <= -100) { - q2 = i2 / 100; - charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - Integer.PACKED_DIGITS[(q2 * 100) - i2], - false); - i2 = q2; - } - - // We know there are at most two digits left at this point. - if (i2 < -9) { - charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - Integer.PACKED_DIGITS[-i2], - false); - } else { - buf[--charPos] = (byte)('0' - i2); - } - - if (negative) { - buf[--charPos] = (byte)'-'; - } - return charPos; - } - /** * Returns the string representation size for a given long value. * diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 139181af0963e..008d3b350fb67 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -250,7 +250,7 @@ static long prepend(long indexCoder, byte[] buf, char value, String prefix) { */ private static long prepend(long indexCoder, byte[] buf, int value) { if (indexCoder < UTF16) { - return Integer.getChars(value, (int)indexCoder, buf); + return StringLatin1.getChars(value, (int)indexCoder, buf); } else { return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; } @@ -285,7 +285,7 @@ static long prepend(long indexCoder, byte[] buf, int value, String prefix) { */ private static long prepend(long indexCoder, byte[] buf, long value) { if (indexCoder < UTF16) { - return Long.getChars(value, (int)indexCoder, buf); + return StringLatin1.getChars(value, (int)indexCoder, buf); } else { return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; } diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 7c12e5711b397..6e2ded228a10a 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -32,8 +32,10 @@ import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; import jdk.internal.vm.annotation.IntrinsicCandidate; +import jdk.internal.vm.annotation.Stable; import static java.lang.String.LATIN1; import static java.lang.String.UTF16; @@ -42,6 +44,42 @@ final class StringLatin1 { + /** + * Each element of the array represents the packaging of two ascii characters based on little endian:

+ *

+     *      00 -> '0' | ('0' << 8) -> 0x3030
+     *      01 -> '1' | ('0' << 8) -> 0x3130
+     *      02 -> '2' | ('0' << 8) -> 0x3230
+     *
+     *     ...
+     *
+     *      10 -> '0' | ('1' << 8) -> 0x3031
+     *      11 -> '1' | ('1' << 8) -> 0x3131
+     *      12 -> '2' | ('1' << 8) -> 0x3231
+     *
+     *     ...
+     *
+     *      97 -> '7' | ('9' << 8) -> 0x3739
+     *      98 -> '8' | ('9' << 8) -> 0x3839
+     *      99 -> '9' | ('9' << 8) -> 0x3939
+     * 
+ */ + @Stable + static final short[] PACKED_DIGITS = new short[] { + 0x3030, 0x3130, 0x3230, 0x3330, 0x3430, 0x3530, 0x3630, 0x3730, 0x3830, 0x3930, + 0x3031, 0x3131, 0x3231, 0x3331, 0x3431, 0x3531, 0x3631, 0x3731, 0x3831, 0x3931, + 0x3032, 0x3132, 0x3232, 0x3332, 0x3432, 0x3532, 0x3632, 0x3732, 0x3832, 0x3932, + 0x3033, 0x3133, 0x3233, 0x3333, 0x3433, 0x3533, 0x3633, 0x3733, 0x3833, 0x3933, + 0x3034, 0x3134, 0x3234, 0x3334, 0x3434, 0x3534, 0x3634, 0x3734, 0x3834, 0x3934, + 0x3035, 0x3135, 0x3235, 0x3335, 0x3435, 0x3535, 0x3635, 0x3735, 0x3835, 0x3935, + 0x3036, 0x3136, 0x3236, 0x3336, 0x3436, 0x3536, 0x3636, 0x3736, 0x3836, 0x3936, + 0x3037, 0x3137, 0x3237, 0x3337, 0x3437, 0x3537, 0x3637, 0x3737, 0x3837, 0x3937, + 0x3038, 0x3138, 0x3238, 0x3338, 0x3438, 0x3538, 0x3638, 0x3738, 0x3838, 0x3938, + 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939 + }; + + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + public static char charAt(byte[] value, int index) { checkIndex(index, value.length); return (char)(value[index] & 0xff); @@ -79,6 +117,130 @@ public static byte[] inflate(byte[] value, int off, int len) { return ret; } + /** + * Places characters representing the integer i into the + * character array buf. The characters are placed into + * the buffer backwards starting with the least significant + * digit at the specified index (exclusive), and working + * backwards from there. + * + * @implNote This method converts positive inputs into negative + * values, to cover the Integer.MIN_VALUE case. Converting otherwise + * (negative to positive) will expose -Integer.MIN_VALUE that overflows + * integer. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, Latin1-encoded + * @return index of the most significant digit or minus sign, if present + */ + static int getChars(int i, int index, byte[] buf) { + int q, r; + int charPos = index; + + boolean negative = i < 0; + if (!negative) { + i = -i; + } + + // Generate two digits per iteration + while (i <= -100) { + q = i / 100; + r = (q * 100) - i; + i = q; + charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; + UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[r], false); + } + + // We know there are at most two digits left at this point. + if (i < -9) { + charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; + UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[-i], false); + } else { + buf[--charPos] = (byte)('0' - i); + } + + if (negative) { + buf[--charPos] = (byte)'-'; + } + return charPos; + } + + /** + * Places characters representing the long i into the + * character array buf. The characters are placed into + * the buffer backwards starting with the least significant + * digit at the specified index (exclusive), and working + * backwards from there. + * + * @implNote This method converts positive inputs into negative + * values, to cover the Long.MIN_VALUE case. Converting otherwise + * (negative to positive) will expose -Long.MIN_VALUE that overflows + * long. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, Latin1-encoded + * @return index of the most significant digit or minus sign, if present + */ + static int getChars(long i, int index, byte[] buf) { + long q; + int charPos = index; + + boolean negative = (i < 0); + if (!negative) { + i = -i; + } + + // Get 2 digits/iteration using longs until quotient fits into an int + while (i <= Integer.MIN_VALUE) { + q = i / 100; + charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; + UNSAFE.putShortUnaligned( + buf, + Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, + PACKED_DIGITS[(int)((q * 100) - i)], + false); + i = q; + } + + // Get 2 digits/iteration using ints + int q2; + int i2 = (int)i; + while (i2 <= -100) { + q2 = i2 / 100; + charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; + UNSAFE.putShortUnaligned( + buf, + Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, + PACKED_DIGITS[(q2 * 100) - i2], + false); + i2 = q2; + } + + // We know there are at most two digits left at this point. + if (i2 < -9) { + charPos -= 2; + assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; + UNSAFE.putShortUnaligned( + buf, + Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, + PACKED_DIGITS[-i2], + false); + } else { + buf[--charPos] = (byte)('0' - i2); + } + + if (negative) { + buf[--charPos] = (byte)'-'; + } + return charPos; + } + public static void getChars(byte[] value, int srcBegin, int srcEnd, char[] dst, int dstBegin) { inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin); } diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index c6faebd25044c..15e056049dc99 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1522,7 +1522,7 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, // been done by the caller. /** - * This is a variant of {@link Integer#getChars(int, int, byte[])}, but for + * This is a variant of {@link StringLatin1#getChars(int, int, byte[])}, but for * UTF-16 coder. * * @param i value to convert @@ -1545,7 +1545,7 @@ static int getChars(int i, int index, byte[] buf) { r = (q * 100) - i; i = q; - int packed = (int) Integer.PACKED_DIGITS[r]; + int packed = (int) StringLatin1.PACKED_DIGITS[r]; int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; @@ -1559,7 +1559,7 @@ static int getChars(int i, int index, byte[] buf) { // We know there are at most two digits left at this point. if (i < -9) { - int packed = (int) Integer.PACKED_DIGITS[-i]; + int packed = (int) StringLatin1.PACKED_DIGITS[-i]; int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; @@ -1580,7 +1580,7 @@ static int getChars(int i, int index, byte[] buf) { } /** - * This is a variant of {@link Long#getChars(long, int, byte[])}, but for + * This is a variant of {@link StringLatin1#getChars(long, int, byte[])}, but for * UTF-16 coder. * * @param i value to convert @@ -1601,7 +1601,7 @@ static int getChars(long i, int index, byte[] buf) { while (i <= Integer.MIN_VALUE) { q = i / 100; - int packed = (int) Integer.PACKED_DIGITS[(int)((q * 100) - i)]; + int packed = (int) StringLatin1.PACKED_DIGITS[(int)((q * 100) - i)]; int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; @@ -1620,7 +1620,7 @@ static int getChars(long i, int index, byte[] buf) { while (i2 <= -100) { q2 = i2 / 100; - int packed = (int) Integer.PACKED_DIGITS[(q2 * 100) - i2]; + int packed = (int) StringLatin1.PACKED_DIGITS[(q2 * 100) - i2]; int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; @@ -1637,7 +1637,7 @@ static int getChars(long i, int index, byte[] buf) { if (i2 < -9) { charPos -= 2; - int packed = (int) Integer.PACKED_DIGITS[-i2]; + int packed = (int) StringLatin1.PACKED_DIGITS[-i2]; int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; From f37ed8a5e6256652c041e08ed53dc0c9eee4191b Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Mon, 4 Sep 2023 23:54:36 +0800 Subject: [PATCH 18/20] add comments --- src/java.base/share/classes/java/lang/StringLatin1.java | 2 ++ src/java.base/share/classes/java/lang/StringUTF16.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 6e2ded228a10a..fec022064671f 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -135,6 +135,7 @@ public static byte[] inflate(byte[] value, int off, int len) { * @return index of the most significant digit or minus sign, if present */ static int getChars(int i, int index, byte[] buf) { + // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. int q, r; int charPos = index; @@ -186,6 +187,7 @@ static int getChars(int i, int index, byte[] buf) { * @return index of the most significant digit or minus sign, if present */ static int getChars(long i, int index, byte[] buf) { + // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. long q; int charPos = index; diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 15e056049dc99..b0209ee937a8c 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1531,6 +1531,7 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, * @return index of the most significant digit or minus sign, if present */ static int getChars(int i, int index, byte[] buf) { + // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. int q, r; int charPos = index; @@ -1589,6 +1590,7 @@ static int getChars(int i, int index, byte[] buf) { * @return index of the most significant digit or minus sign, if present */ static int getChars(long i, int index, byte[] buf) { + // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. long q; int charPos = index; From 18904a9329ab620df25ca01504b320b77094d026 Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Tue, 5 Sep 2023 08:00:12 +0800 Subject: [PATCH 19/20] update copyright date info --- .../share/classes/java/lang/AbstractStringBuilder.java | 2 +- src/java.base/share/classes/java/lang/StringConcatHelper.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index 2be557dc4bc84..b41b5db37837a 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 008d3b350fb67..eddfc7e649660 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From c0f42a7cfcb3783423689bb05c21b3313d2644f6 Mon Sep 17 00:00:00 2001 From: "shaojin.wensj" Date: Thu, 7 Sep 2023 06:16:20 +0800 Subject: [PATCH 20/20] use ByteArrayLittleEndian --- .../share/classes/java/lang/StringLatin1.java | 31 +++------------ .../share/classes/java/lang/StringUTF16.java | 39 +++---------------- 2 files changed, 12 insertions(+), 58 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index fec022064671f..f6e2acd2fe6c6 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -32,8 +32,8 @@ import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; +import jdk.internal.util.ByteArrayLittleEndian; import jdk.internal.vm.annotation.IntrinsicCandidate; import jdk.internal.vm.annotation.Stable; @@ -78,8 +78,6 @@ final class StringLatin1 { 0x3039, 0x3139, 0x3239, 0x3339, 0x3439, 0x3539, 0x3639, 0x3739, 0x3839, 0x3939 }; - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - public static char charAt(byte[] value, int index) { checkIndex(index, value.length); return (char)(value[index] & 0xff); @@ -150,15 +148,13 @@ static int getChars(int i, int index, byte[] buf) { r = (q * 100) - i; i = q; charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[r], false); + ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[r]); } // We know there are at most two digits left at this point. if (i < -9) { charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned(buf, Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, PACKED_DIGITS[-i], false); + ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[-i]); } else { buf[--charPos] = (byte)('0' - i); } @@ -200,12 +196,7 @@ static int getChars(long i, int index, byte[] buf) { while (i <= Integer.MIN_VALUE) { q = i / 100; charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - PACKED_DIGITS[(int)((q * 100) - i)], - false); + ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[(int)((q * 100) - i)]); i = q; } @@ -215,24 +206,14 @@ static int getChars(long i, int index, byte[] buf) { while (i2 <= -100) { q2 = i2 / 100; charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - PACKED_DIGITS[(q2 * 100) - i2], - false); + ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[(q2 * 100) - i2]); i2 = q2; } // We know there are at most two digits left at this point. if (i2 < -9) { charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putShortUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + charPos, - PACKED_DIGITS[-i2], - false); + ByteArrayLittleEndian.setShort(buf, charPos, PACKED_DIGITS[-i2]); } else { buf[--charPos] = (byte)('0' - i2); } diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index b0209ee937a8c..db9bdb11864b9 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -32,8 +32,8 @@ import java.util.function.IntConsumer; import java.util.stream.Stream; import java.util.stream.StreamSupport; -import jdk.internal.misc.Unsafe; import jdk.internal.util.ArraysSupport; +import jdk.internal.util.ByteArrayLittleEndian; import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -1514,8 +1514,6 @@ public static int lastIndexOfLatin1(byte[] src, int srcCount, } } - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; // Used by trusted callers. Assumes all necessary bounds checks have @@ -1550,12 +1548,7 @@ static int getChars(int i, int index, byte[] buf) { int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putIntUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - inflated, - false); + ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated); } // We know there are at most two digits left at this point. @@ -1564,12 +1557,7 @@ static int getChars(int i, int index, byte[] buf) { int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putIntUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - inflated, - false); + ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated); } else { putChar(buf, --charPos, '0' - i); } @@ -1607,12 +1595,7 @@ static int getChars(long i, int index, byte[] buf) { int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putIntUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - inflated, - false); + ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated); i = q; } @@ -1626,12 +1609,7 @@ static int getChars(long i, int index, byte[] buf) { int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); charPos -= 2; - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putIntUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - inflated, - false); + ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated); i2 = q2; } @@ -1642,12 +1620,7 @@ static int getChars(long i, int index, byte[] buf) { int packed = (int) StringLatin1.PACKED_DIGITS[-i2]; int inflated = ((packed & 0xFF00) << 8) | (packed & 0xFF); - assert charPos >= 0 && charPos < buf.length : "Trusted caller missed bounds check"; - UNSAFE.putIntUnaligned( - buf, - Unsafe.ARRAY_BYTE_BASE_OFFSET + (charPos << 1), - inflated, - false); + ByteArrayLittleEndian.setInt(buf, charPos << 1, inflated); } else { putChar(buf, --charPos, '0' - i2); }