From 5e815b63e0577735b1540191ab71e57fe4e95967 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sun, 9 Jun 2024 13:22:32 +0800 Subject: [PATCH 01/17] Optimization for StringBuilder append(boolean) & appendNull --- .../java/lang/AbstractStringBuilder.java | 41 ++++++----- .../share/classes/java/lang/StringUTF16.java | 34 ++++----- .../TestStringUTF16IntrinsicRangeChecks.java | 23 ------ .../patches/java.base/java/lang/Helper.java | 8 -- .../bench/java/lang/StringBuilders.java | 73 ++++++++++++++++--- 5 files changed, 96 insertions(+), 83 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index 187e041e6745a..44e07925d8ef8 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -635,18 +635,18 @@ public AbstractStringBuilder append(CharSequence s) { } private AbstractStringBuilder appendNull() { - ensureCapacityInternal(count + 4); int count = this.count; + ensureCapacityInternal(count + 4); byte[] val = this.value; if (isLatin1()) { - val[count++] = 'n'; - val[count++] = 'u'; - val[count++] = 'l'; - val[count++] = 'l'; + val[count ] = 'n'; + val[count + 1] = 'u'; + val[count + 2] = 'l'; + val[count + 3] = 'l'; } else { - count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l'); + StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l'); } - this.count = count; + this.count = count + 4; return this; } @@ -766,30 +766,31 @@ public AbstractStringBuilder append(char[] str, int offset, int len) { * @return a reference to this object. */ public AbstractStringBuilder append(boolean b) { - ensureCapacityInternal(count + (b ? 4 : 5)); int count = this.count; + int spaceNeeded = count + (b ? 4 : 5); + ensureCapacityInternal(spaceNeeded); byte[] val = this.value; if (isLatin1()) { if (b) { - val[count++] = 't'; - val[count++] = 'r'; - val[count++] = 'u'; - val[count++] = 'e'; + val[count ] = 't'; + val[count + 1] = 'r'; + val[count + 2] = 'u'; + val[count + 3] = 'e'; } else { - val[count++] = 'f'; - val[count++] = 'a'; - val[count++] = 'l'; - val[count++] = 's'; - val[count++] = 'e'; + val[count ] = 'f'; + val[count + 1] = 'a'; + val[count + 2] = 'l'; + val[count + 3] = 's'; + val[count + 4] = 'e'; } } else { if (b) { - count = StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e'); + StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e'); } else { - count = StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e'); + StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e'); } } - this.count = count; + this.count = spaceNeeded; return this; } diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 000483f29bc9e..855dcf38d2cfc 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1548,27 +1548,19 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { return true; } - public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { - int end = i + 4; - checkBoundsBeginEnd(i, end, value); - putChar(value, i++, c1); - putChar(value, i++, c2); - putChar(value, i++, c3); - putChar(value, i++, c4); - assert(i == end); - return end; - } - - public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { - int end = i + 5; - checkBoundsBeginEnd(i, end, value); - putChar(value, i++, c1); - putChar(value, i++, c2); - putChar(value, i++, c3); - putChar(value, i++, c4); - putChar(value, i++, c5); - assert(i == end); - return end; + public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + putChar(value, i , c1); + putChar(value, i + 1, c2); + putChar(value, i + 2, c3); + putChar(value, i + 3, c4); + } + + public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + putChar(value, i , c1); + putChar(value, i + 1, c2); + putChar(value, i + 2, c3); + putChar(value, i + 3, c4); + putChar(value, i + 4, c5); } public static char charAt(byte[] value, int index) { diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java index 9cd40ac504fd6..c4e3ecd3c38ec 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java @@ -108,13 +108,6 @@ public static void main(String[] args) throws Exception { throw new AssertionError("append"); } - putCharsAt(val2, -1, '1', '2', '3', '4'); - putCharsAt(val2, 0, '1', '2', '3', '4'); - putCharsAt(val2, 2, '1', '2', '3', '4'); - putCharsAt(val2, -1, '1', '2', '3', '4', '5'); - putCharsAt(val2, 0, '1', '2', '3', '4', '5'); - putCharsAt(val2, 2, '1', '2', '3', '4', '5'); - reverse(valHigh, -1); reverse(valHigh, 2); reverse(valLow, -1); @@ -248,22 +241,6 @@ static void contentEquals(byte[] v, CharSequence cs, int len) { } } - static void putCharsAt(byte[] v, int i, char c1, char c2, char c3, char c4) { - try { - Helper.putCharsAt(v, i, c1, c2, c3, c4); - throw new AssertionError("putCharsAt"); - } catch (IndexOutOfBoundsException io) { - } - } - - static void putCharsAt(byte[] v, int i, char c1, char c2, char c3, char c4, char c5) { - try { - Helper.putCharsAt(v, i, c1, c2, c3, c4, c5); - throw new AssertionError("putCharsAt"); - } catch (IndexOutOfBoundsException io) { - } - } - static void reverse(byte[] v, int len) { try { Helper.reverse(v, len); diff --git a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index a24d7b98ada52..c41846ba26295 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -132,14 +132,6 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { return StringUTF16.contentEquals(value, cs, len); } - public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { - return StringUTF16.putCharsAt(value, i, c1, c2, c3, c4); - } - - public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { - return StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5); - } - public static char charAt(byte[] value, int index) { return StringUTF16.charAt(value, index); } diff --git a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java index 29827b7f03a2f..7c2177758fff0 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java +++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java @@ -226,17 +226,68 @@ public String toStringCharWithInt8() { @Benchmark - public String toStringCharWithBool8() { - StringBuilder result = new StringBuilder(); - result.append(true); - result.append(false); - result.append(true); - result.append(true); - result.append(false); - result.append(true); - result.append(false); - result.append(false); - return result.toString(); + public int toStringCharWithBool8Latin1() { + StringBuilder buf = sbLatin1; + buf.delete(0, buf.length()); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(false); + buf.append(false); + return buf.length(); + } + + + @Benchmark + public int toStringCharWithBool8Utf16() { + StringBuilder buf = sbUtf16; + buf.delete(0, buf.length()); + buf.append('\uFF16'); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(true); + buf.append(false); + buf.append(true); + buf.append(false); + buf.append(false); + return buf.length(); + } + + + @Benchmark + public int toStringCharWithNull8Latin1() { + StringBuilder buf = sbLatin1; + buf.delete(0, buf.length()); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + return buf.length(); + } + + + @Benchmark + public int toStringCharWithNull8Utf16() { + StringBuilder buf = sbUtf16; + buf.delete(0, buf.length()); + buf.append('\uFF16'); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + buf.append((String) null); + return buf.length(); } From 0cbaa5ac04873373131f1a7216353a5af5b3e48e Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Tue, 11 Jun 2024 13:20:38 +0800 Subject: [PATCH 02/17] optimize to combining values into larger stores --- .../share/classes/java/lang/StringUTF16.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 855dcf38d2cfc..c255183e8947e 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1549,18 +1549,25 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { } public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { - putChar(value, i , c1); - putChar(value, i + 1, c2); - putChar(value, i + 2, c3); - putChar(value, i + 3, c4); + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + putChar0(value, i , c1); + putChar0(value, i + 1, c2); + putChar0(value, i + 2, c3); + putChar0(value, i + 3, c4); } public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { - putChar(value, i , c1); - putChar(value, i + 1, c2); - putChar(value, i + 2, c3); - putChar(value, i + 3, c4); - putChar(value, i + 4, c5); + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores + putChar0(value, i , c1); + putChar0(value, i + 1, c2); + putChar0(value, i + 2, c3); + putChar0(value, i + 3, c4); + putChar0(value, i + 4, c5); + } + + private static void putChar0(byte[] val, int index, int c) { + val[index ] = (byte)(c >> HI_BYTE_SHIFT); + val[index + 1] = (byte)(c >> LO_BYTE_SHIFT); } public static char charAt(byte[] value, int index) { From f96cde4e79e12e2ea46e6061f918a69f11d59985 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Tue, 11 Jun 2024 13:38:55 +0800 Subject: [PATCH 03/17] bug fix --- .../share/classes/java/lang/StringUTF16.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index c255183e8947e..23635a25b7d9f 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1550,24 +1550,26 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + i <<= 1; putChar0(value, i , c1); - putChar0(value, i + 1, c2); - putChar0(value, i + 2, c3); - putChar0(value, i + 3, c4); + putChar0(value, i + 2, c2); + putChar0(value, i + 4, c3); + putChar0(value, i + 6, c4); } public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores + i <<= 1; putChar0(value, i , c1); - putChar0(value, i + 1, c2); - putChar0(value, i + 2, c3); - putChar0(value, i + 3, c4); - putChar0(value, i + 4, c5); + putChar0(value, i + 2, c2); + putChar0(value, i + 4, c3); + putChar0(value, i + 6, c4); + putChar0(value, i + 8, c5); } - private static void putChar0(byte[] val, int index, int c) { - val[index ] = (byte)(c >> HI_BYTE_SHIFT); - val[index + 1] = (byte)(c >> LO_BYTE_SHIFT); + private static void putChar0(byte[] value, int i, int c) { + value[i ] = (byte)(c >> HI_BYTE_SHIFT); + value[i + 1] = (byte)(c >> LO_BYTE_SHIFT); } public static char charAt(byte[] value, int index) { From 27a3050a73ec4a65edbdb23383237a08037e0462 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Tue, 11 Jun 2024 15:24:55 +0800 Subject: [PATCH 04/17] revert --- .../share/classes/java/lang/StringUTF16.java | 27 +++++++------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 23635a25b7d9f..855dcf38d2cfc 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1549,27 +1549,18 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { } public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { - // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. - i <<= 1; - putChar0(value, i , c1); - putChar0(value, i + 2, c2); - putChar0(value, i + 4, c3); - putChar0(value, i + 6, c4); + putChar(value, i , c1); + putChar(value, i + 1, c2); + putChar(value, i + 2, c3); + putChar(value, i + 3, c4); } public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { - // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores - i <<= 1; - putChar0(value, i , c1); - putChar0(value, i + 2, c2); - putChar0(value, i + 4, c3); - putChar0(value, i + 6, c4); - putChar0(value, i + 8, c5); - } - - private static void putChar0(byte[] value, int i, int c) { - value[i ] = (byte)(c >> HI_BYTE_SHIFT); - value[i + 1] = (byte)(c >> LO_BYTE_SHIFT); + putChar(value, i , c1); + putChar(value, i + 1, c2); + putChar(value, i + 2, c3); + putChar(value, i + 3, c4); + putChar(value, i + 4, c5); } public static char charAt(byte[] value, int index) { From dd97cff37d3543b89e2ad655f7ee54df03a90f76 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Wed, 12 Jun 2024 23:12:13 +0800 Subject: [PATCH 05/17] optimize to combining values into larger stores --- .../share/classes/java/lang/StringUTF16.java | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 855dcf38d2cfc..2e40986f04c89 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -43,7 +43,6 @@ import static java.lang.String.LATIN1; final class StringUTF16 { - // Return a new byte array for a UTF16-coded string for len chars // Throw an exception if out of range public static byte[] newBytesFor(int len) { @@ -1549,18 +1548,26 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { } public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { - putChar(value, i , c1); - putChar(value, i + 1, c2); - putChar(value, i + 2, c3); - putChar(value, i + 3, c4); + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + putChar1(value, i , c1); + putChar1(value, i + 1, c2); + putChar1(value, i + 2, c3); + putChar1(value, i + 3, c4); } public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { - putChar(value, i , c1); - putChar(value, i + 1, c2); - putChar(value, i + 2, c3); - putChar(value, i + 3, c4); - putChar(value, i + 4, c5); + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + putChar1(value, i , c1); + putChar1(value, i + 1, c2); + putChar1(value, i + 2, c3); + putChar1(value, i + 3, c4); + putChar1(value, i + 4, c5); + } + + static void putChar1(byte[] value, int i, char c) { + int address = Unsafe.ARRAY_BYTE_BASE_OFFSET + (i << 1); + Unsafe.getUnsafe().putByte(value, address , (byte)(c >> HI_BYTE_SHIFT)); + Unsafe.getUnsafe().putByte(value, address + 1, (byte)(c >> LO_BYTE_SHIFT)); } public static char charAt(byte[] value, int index) { From 67be25c7e1d2aebbc8f0c1bdb3828d194b049480 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 13 Jun 2024 05:37:11 +0800 Subject: [PATCH 06/17] StringLatin1 & StringUTF16 use the same logic --- .../java/lang/AbstractStringBuilder.java | 16 ++----- .../share/classes/java/lang/StringLatin1.java | 22 +++++++++ .../share/classes/java/lang/StringUTF16.java | 47 +++++++++++-------- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index 44e07925d8ef8..d04b03c49062c 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -639,10 +639,7 @@ private AbstractStringBuilder appendNull() { ensureCapacityInternal(count + 4); byte[] val = this.value; if (isLatin1()) { - val[count ] = 'n'; - val[count + 1] = 'u'; - val[count + 2] = 'l'; - val[count + 3] = 'l'; + StringLatin1.putCharsAt(val, count, 'n', 'u', 'l', 'l'); } else { StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l'); } @@ -772,16 +769,9 @@ public AbstractStringBuilder append(boolean b) { byte[] val = this.value; if (isLatin1()) { if (b) { - val[count ] = 't'; - val[count + 1] = 'r'; - val[count + 2] = 'u'; - val[count + 3] = 'e'; + StringLatin1.putCharsAt(val, count, 't', 'r', 'u', 'e'); } else { - val[count ] = 'f'; - val[count + 1] = 'a'; - val[count + 2] = 'l'; - val[count + 3] = 's'; - val[count + 4] = 'e'; + StringLatin1.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e'); } } else { if (b) { diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index abec36af1d9d7..28f8c8d47a634 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -32,6 +32,7 @@ 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.DecimalDigits; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -824,6 +825,27 @@ static Stream lines(byte[] value) { return StreamSupport.stream(LinesSpliterator.spliterator(value), false); } + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { + assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + Unsafe UNSAFE = Unsafe.getUnsafe(); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c2)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c3)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c4)); + } + + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) { + assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check"; + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + Unsafe UNSAFE = Unsafe.getUnsafe(); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c2)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c3)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c4)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 4, (byte)(c5)); + } + public static void putChar(byte[] val, int index, int c) { //assert (canEncode(c)); val[index] = (byte)(c); diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 2e40986f04c89..77b4fe5d9bd29 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1547,27 +1547,36 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { return true; } - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. - putChar1(value, i , c1); - putChar1(value, i + 1, c2); - putChar1(value, i + 2, c3); - putChar1(value, i + 3, c4); - } - - public static void putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + index <<= 1; + assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; + Unsafe UNSAFE = Unsafe.getUnsafe(); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c1 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c2 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c2 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 4, (byte)(c3 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 5, (byte)(c3 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 6, (byte)(c4 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 7, (byte)(c4 >> LO_BYTE_SHIFT)); + } + + static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) { // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. - putChar1(value, i , c1); - putChar1(value, i + 1, c2); - putChar1(value, i + 2, c3); - putChar1(value, i + 3, c4); - putChar1(value, i + 4, c5); - } - - static void putChar1(byte[] value, int i, char c) { - int address = Unsafe.ARRAY_BYTE_BASE_OFFSET + (i << 1); - Unsafe.getUnsafe().putByte(value, address , (byte)(c >> HI_BYTE_SHIFT)); - Unsafe.getUnsafe().putByte(value, address + 1, (byte)(c >> LO_BYTE_SHIFT)); + assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check"; + index <<= 1; + Unsafe UNSAFE = Unsafe.getUnsafe(); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c1 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c2 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c2 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 4, (byte)(c3 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 5, (byte)(c3 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 6, (byte)(c4 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 7, (byte)(c4 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 8, (byte)(c5 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 9, (byte)(c5 >> LO_BYTE_SHIFT)); } public static char charAt(byte[] value, int index) { From 7b3cf602dae51508a1bfaea22667f72962e5e9bb Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 13 Jun 2024 07:22:59 +0800 Subject: [PATCH 07/17] fix assert --- src/java.base/share/classes/java/lang/StringUTF16.java | 2 +- 1 file changed, 1 insertion(+), 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 77b4fe5d9bd29..c3b36661a98b4 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1549,8 +1549,8 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. - index <<= 1; assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; + index <<= 1; Unsafe UNSAFE = Unsafe.getUnsafe(); UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1 >> HI_BYTE_SHIFT)); UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c1 >> LO_BYTE_SHIFT)); From ad1af385aaac3fcf2c8743bf2207bb2339d68e2b Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 13 Jun 2024 07:45:57 +0800 Subject: [PATCH 08/17] code format & use long address --- .../share/classes/java/lang/StringLatin1.java | 22 +++++---- .../share/classes/java/lang/StringUTF16.java | 46 ++++++++++--------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 28f8c8d47a634..85aeb7c605d4f 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -828,22 +828,26 @@ static Stream lines(byte[] value) { static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index; Unsafe UNSAFE = Unsafe.getUnsafe(); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c2)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c3)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c4)); + + UNSAFE.putByte(val, address , (byte)(c1)); + UNSAFE.putByte(val, address + 1, (byte)(c2)); + UNSAFE.putByte(val, address + 2, (byte)(c3)); + UNSAFE.putByte(val, address + 3, (byte)(c4)); } static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) { assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check"; // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index; Unsafe UNSAFE = Unsafe.getUnsafe(); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c2)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c3)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c4)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 4, (byte)(c5)); + + UNSAFE.putByte(val, address , (byte)(c1)); + UNSAFE.putByte(val, address + 1, (byte)(c2)); + UNSAFE.putByte(val, address + 2, (byte)(c3)); + UNSAFE.putByte(val, address + 3, (byte)(c4)); + UNSAFE.putByte(val, address + 4, (byte)(c5)); } public static void putChar(byte[] val, int index, int c) { diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index c3b36661a98b4..543e3618b5a66 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1548,35 +1548,37 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { } static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { - // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; - index <<= 1; + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + (index << 1); Unsafe UNSAFE = Unsafe.getUnsafe(); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c1 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c2 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c2 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 4, (byte)(c3 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 5, (byte)(c3 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 6, (byte)(c4 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 7, (byte)(c4 >> LO_BYTE_SHIFT)); + + UNSAFE.putByte(val, address , (byte)(c1 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 1, (byte)(c1 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 2, (byte)(c2 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 3, (byte)(c2 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 4, (byte)(c3 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 5, (byte)(c3 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 6, (byte)(c4 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 7, (byte)(c4 >> LO_BYTE_SHIFT)); } static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) { - // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check"; - index <<= 1; + // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. + long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + (index << 1); Unsafe UNSAFE = Unsafe.getUnsafe(); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index , (byte)(c1 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 1, (byte)(c1 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 2, (byte)(c2 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 3, (byte)(c2 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 4, (byte)(c3 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 5, (byte)(c3 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 6, (byte)(c4 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 7, (byte)(c4 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 8, (byte)(c5 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, Unsafe.ARRAY_BYTE_BASE_OFFSET + index + 9, (byte)(c5 >> LO_BYTE_SHIFT)); + + UNSAFE.putByte(val, address , (byte)(c1 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 1, (byte)(c1 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 2, (byte)(c2 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 3, (byte)(c2 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 4, (byte)(c3 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 5, (byte)(c3 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 6, (byte)(c4 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 7, (byte)(c4 >> LO_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 8, (byte)(c5 >> HI_BYTE_SHIFT)); + UNSAFE.putByte(val, address + 9, (byte)(c5 >> LO_BYTE_SHIFT)); } public static char charAt(byte[] value, int index) { From 22d45124ac6125222f6f833345aef7dc1e48c061 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 13 Jun 2024 09:31:54 +0800 Subject: [PATCH 09/17] rename benchmark --- .../micro/org/openjdk/bench/java/lang/StringBuilders.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java index 7c2177758fff0..c61254f593037 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java +++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java @@ -226,7 +226,7 @@ public String toStringCharWithInt8() { @Benchmark - public int toStringCharWithBool8Latin1() { + public int appendWithBool8Latin1() { StringBuilder buf = sbLatin1; buf.delete(0, buf.length()); buf.append(true); @@ -242,7 +242,7 @@ public int toStringCharWithBool8Latin1() { @Benchmark - public int toStringCharWithBool8Utf16() { + public int appendWithBool8Utf16() { StringBuilder buf = sbUtf16; buf.delete(0, buf.length()); buf.append('\uFF16'); @@ -259,7 +259,7 @@ public int toStringCharWithBool8Utf16() { @Benchmark - public int toStringCharWithNull8Latin1() { + public int appendWithNull8Latin1() { StringBuilder buf = sbLatin1; buf.delete(0, buf.length()); buf.append((String) null); @@ -275,7 +275,7 @@ public int toStringCharWithNull8Latin1() { @Benchmark - public int toStringCharWithNull8Utf16() { + public int appendWithNull8Utf16() { StringBuilder buf = sbUtf16; buf.delete(0, buf.length()); buf.append('\uFF16'); From b5ad8e70928c547d134d0e4a532441cad9a7e4a2 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Fri, 14 Jun 2024 09:14:32 +0800 Subject: [PATCH 10/17] optimization for x64 --- .../share/classes/java/lang/AbstractStringBuilder.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index d04b03c49062c..f7821cc05f1e9 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -635,8 +635,8 @@ public AbstractStringBuilder append(CharSequence s) { } private AbstractStringBuilder appendNull() { - int count = this.count; ensureCapacityInternal(count + 4); + int count = this.count; byte[] val = this.value; if (isLatin1()) { StringLatin1.putCharsAt(val, count, 'n', 'u', 'l', 'l'); @@ -763,9 +763,8 @@ public AbstractStringBuilder append(char[] str, int offset, int len) { * @return a reference to this object. */ public AbstractStringBuilder append(boolean b) { + ensureCapacityInternal(count + (b ? 4 : 5)); int count = this.count; - int spaceNeeded = count + (b ? 4 : 5); - ensureCapacityInternal(spaceNeeded); byte[] val = this.value; if (isLatin1()) { if (b) { @@ -780,7 +779,7 @@ public AbstractStringBuilder append(boolean b) { StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e'); } } - this.count = spaceNeeded; + this.count = count + (b ? 4 : 5); return this; } From 1a012f1c069bbf1364f358b1574d83d65fa6e1ee Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 15 Jun 2024 01:25:11 +0800 Subject: [PATCH 11/17] copyright 2024 --- .../share/classes/java/lang/AbstractStringBuilder.java | 2 +- .../intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java | 2 +- .../jtreg/compiler/patches/java.base/java/lang/Helper.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index f7821cc05f1e9..8958aa868a72b 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, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java index c4e3ecd3c38ec..50c716bed746d 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index c41846ba26295..f41512334676a 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, 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 3db11b214d4395940d308e3c43bb93ba01f5c357 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 17 Jun 2024 09:23:17 +0800 Subject: [PATCH 12/17] `delete` -> `setLength` --- .../micro/org/openjdk/bench/java/lang/StringBuilders.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java index c61254f593037..b1ff36ffbfdfa 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java +++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java @@ -228,7 +228,7 @@ public String toStringCharWithInt8() { @Benchmark public int appendWithBool8Latin1() { StringBuilder buf = sbLatin1; - buf.delete(0, buf.length()); + buf.setLength(0); buf.append(true); buf.append(false); buf.append(true); @@ -244,7 +244,7 @@ public int appendWithBool8Latin1() { @Benchmark public int appendWithBool8Utf16() { StringBuilder buf = sbUtf16; - buf.delete(0, buf.length()); + buf.setLength(0); buf.append('\uFF16'); buf.append(true); buf.append(false); @@ -261,7 +261,7 @@ public int appendWithBool8Utf16() { @Benchmark public int appendWithNull8Latin1() { StringBuilder buf = sbLatin1; - buf.delete(0, buf.length()); + buf.setLength(0); buf.append((String) null); buf.append((String) null); buf.append((String) null); @@ -277,7 +277,7 @@ public int appendWithNull8Latin1() { @Benchmark public int appendWithNull8Utf16() { StringBuilder buf = sbUtf16; - buf.delete(0, buf.length()); + buf.setLength(0); buf.append('\uFF16'); buf.append((String) null); buf.append((String) null); From fa72999a3247235cf21afd894e6b50363af64303 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 17 Jun 2024 11:03:38 +0800 Subject: [PATCH 13/17] Utf16 case remove `append first utf16 char` --- test/micro/org/openjdk/bench/java/lang/StringBuilders.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java index b1ff36ffbfdfa..a6b43ca0194c2 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java +++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java @@ -245,7 +245,6 @@ public int appendWithBool8Latin1() { public int appendWithBool8Utf16() { StringBuilder buf = sbUtf16; buf.setLength(0); - buf.append('\uFF16'); buf.append(true); buf.append(false); buf.append(true); @@ -278,7 +277,6 @@ public int appendWithNull8Latin1() { public int appendWithNull8Utf16() { StringBuilder buf = sbUtf16; buf.setLength(0); - buf.append('\uFF16'); buf.append((String) null); buf.append((String) null); buf.append((String) null); From 6be002ac102ffdbc63e12a7f04d243fe485ae759 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sun, 23 Jun 2024 01:56:43 +0800 Subject: [PATCH 14/17] private static final field `UNSAFE` --- src/java.base/share/classes/java/lang/StringLatin1.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index 85aeb7c605d4f..c12b8afc21f37 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -43,6 +43,8 @@ import static java.lang.String.checkOffset; final class StringLatin1 { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + public static char charAt(byte[] value, int index) { checkIndex(index, value.length); return (char)(value[index] & 0xff); @@ -829,8 +831,6 @@ static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index; - Unsafe UNSAFE = Unsafe.getUnsafe(); - UNSAFE.putByte(val, address , (byte)(c1)); UNSAFE.putByte(val, address + 1, (byte)(c2)); UNSAFE.putByte(val, address + 2, (byte)(c3)); @@ -841,8 +841,6 @@ static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, in assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check"; // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index; - Unsafe UNSAFE = Unsafe.getUnsafe(); - UNSAFE.putByte(val, address , (byte)(c1)); UNSAFE.putByte(val, address + 1, (byte)(c2)); UNSAFE.putByte(val, address + 2, (byte)(c3)); From 9d9c8eb8f913329e4e5579a4adf9580fbeef1ab8 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 6 Jul 2024 18:28:41 +0800 Subject: [PATCH 15/17] replace unsafe with putChar --- .../share/classes/java/lang/StringUTF16.java | 36 +++++-------------- 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index 543e3618b5a66..f04b991827f7f 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -1549,36 +1549,18 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) { assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check"; - // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. - long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + (index << 1); - Unsafe UNSAFE = Unsafe.getUnsafe(); - - UNSAFE.putByte(val, address , (byte)(c1 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 1, (byte)(c1 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 2, (byte)(c2 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 3, (byte)(c2 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 4, (byte)(c3 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 5, (byte)(c3 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 6, (byte)(c4 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 7, (byte)(c4 >> LO_BYTE_SHIFT)); + putChar(val, index , c1); + putChar(val, index + 1, c2); + putChar(val, index + 2, c3); + putChar(val, index + 3, c4); } static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) { - assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check"; - // Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores. - long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + (index << 1); - Unsafe UNSAFE = Unsafe.getUnsafe(); - - UNSAFE.putByte(val, address , (byte)(c1 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 1, (byte)(c1 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 2, (byte)(c2 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 3, (byte)(c2 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 4, (byte)(c3 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 5, (byte)(c3 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 6, (byte)(c4 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 7, (byte)(c4 >> LO_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 8, (byte)(c5 >> HI_BYTE_SHIFT)); - UNSAFE.putByte(val, address + 9, (byte)(c5 >> LO_BYTE_SHIFT)); + putChar(val, index , c1); + putChar(val, index + 1, c2); + putChar(val, index + 2, c3); + putChar(val, index + 3, c4); + putChar(val, index + 4, c5); } public static char charAt(byte[] value, int index) { From 3c55f15e57db1ca33c9a79846f42398f674d72a5 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Mon, 23 Sep 2024 00:10:07 +0800 Subject: [PATCH 16/17] revert test --- .../TestStringUTF16IntrinsicRangeChecks.java | 25 ++++++++++++++++++- .../patches/java.base/java/lang/Helper.java | 10 ++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java index 50c716bed746d..9cd40ac504fd6 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestStringUTF16IntrinsicRangeChecks.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -108,6 +108,13 @@ public static void main(String[] args) throws Exception { throw new AssertionError("append"); } + putCharsAt(val2, -1, '1', '2', '3', '4'); + putCharsAt(val2, 0, '1', '2', '3', '4'); + putCharsAt(val2, 2, '1', '2', '3', '4'); + putCharsAt(val2, -1, '1', '2', '3', '4', '5'); + putCharsAt(val2, 0, '1', '2', '3', '4', '5'); + putCharsAt(val2, 2, '1', '2', '3', '4', '5'); + reverse(valHigh, -1); reverse(valHigh, 2); reverse(valLow, -1); @@ -241,6 +248,22 @@ static void contentEquals(byte[] v, CharSequence cs, int len) { } } + static void putCharsAt(byte[] v, int i, char c1, char c2, char c3, char c4) { + try { + Helper.putCharsAt(v, i, c1, c2, c3, c4); + throw new AssertionError("putCharsAt"); + } catch (IndexOutOfBoundsException io) { + } + } + + static void putCharsAt(byte[] v, int i, char c1, char c2, char c3, char c4, char c5) { + try { + Helper.putCharsAt(v, i, c1, c2, c3, c4, c5); + throw new AssertionError("putCharsAt"); + } catch (IndexOutOfBoundsException io) { + } + } + static void reverse(byte[] v, int len) { try { Helper.reverse(v, len); diff --git a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index f41512334676a..daa4afa77607f 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -132,6 +132,16 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { return StringUTF16.contentEquals(value, cs, len); } + public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + StringUTF16.putCharsAt(value, i, c1, c2, c3, c4); + return i + 4; + } + + public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5); + return i + 5; + } + public static char charAt(byte[] value, int index) { return StringUTF16.charAt(value, index); } From ae054771a2db45062507bb15d21322e6dd7212f2 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Tue, 24 Sep 2024 07:19:53 +0800 Subject: [PATCH 17/17] fix build error --- .../compiler/patches/java.base/java/lang/Helper.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java index daa4afa77607f..5ecc01aa2bc29 100644 --- a/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java +++ b/test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java @@ -133,13 +133,17 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) { } public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) { + int end = i + 4; + StringUTF16.checkBoundsBeginEnd(i, end, value); StringUTF16.putCharsAt(value, i, c1, c2, c3, c4); - return i + 4; + return end; } public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) { + int end = i + 5; + StringUTF16.checkBoundsBeginEnd(i, end, value); StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5); - return i + 5; + return end; } public static char charAt(byte[] value, int index) {