Skip to content

Commit 5890d94

Browse files
committedNov 5, 2024
8333893: Optimization for StringBuilder append boolean & null
Reviewed-by: liach
1 parent c33a8f5 commit 5890d94

File tree

5 files changed

+115
-54
lines changed

5 files changed

+115
-54
lines changed
 

‎src/java.base/share/classes/java/lang/AbstractStringBuilder.java

+8-18
Original file line numberDiff line numberDiff line change
@@ -640,14 +640,11 @@ private AbstractStringBuilder appendNull() {
640640
int count = this.count;
641641
byte[] val = this.value;
642642
if (isLatin1()) {
643-
val[count++] = 'n';
644-
val[count++] = 'u';
645-
val[count++] = 'l';
646-
val[count++] = 'l';
643+
StringLatin1.putCharsAt(val, count, 'n', 'u', 'l', 'l');
647644
} else {
648-
count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
645+
StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
649646
}
650-
this.count = count;
647+
this.count = count + 4;
651648
return this;
652649
}
653650

@@ -772,25 +769,18 @@ public AbstractStringBuilder append(boolean b) {
772769
byte[] val = this.value;
773770
if (isLatin1()) {
774771
if (b) {
775-
val[count++] = 't';
776-
val[count++] = 'r';
777-
val[count++] = 'u';
778-
val[count++] = 'e';
772+
StringLatin1.putCharsAt(val, count, 't', 'r', 'u', 'e');
779773
} else {
780-
val[count++] = 'f';
781-
val[count++] = 'a';
782-
val[count++] = 'l';
783-
val[count++] = 's';
784-
val[count++] = 'e';
774+
StringLatin1.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
785775
}
786776
} else {
787777
if (b) {
788-
count = StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e');
778+
StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e');
789779
} else {
790-
count = StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
780+
StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
791781
}
792782
}
793-
this.count = count;
783+
this.count = count + (b ? 4 : 5);
794784
return this;
795785
}
796786

‎src/java.base/share/classes/java/lang/StringLatin1.java

+24
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import java.util.function.IntConsumer;
3333
import java.util.stream.Stream;
3434
import java.util.stream.StreamSupport;
35+
import jdk.internal.misc.Unsafe;
3536
import jdk.internal.util.ArraysSupport;
3637
import jdk.internal.util.DecimalDigits;
3738
import jdk.internal.vm.annotation.IntrinsicCandidate;
@@ -42,6 +43,8 @@
4243
import static java.lang.String.checkOffset;
4344

4445
final class StringLatin1 {
46+
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
47+
4548
public static char charAt(byte[] value, int index) {
4649
checkIndex(index, value.length);
4750
return (char)(value[index] & 0xff);
@@ -824,6 +827,27 @@ static Stream<String> lines(byte[] value) {
824827
return StreamSupport.stream(LinesSpliterator.spliterator(value), false);
825828
}
826829

830+
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) {
831+
assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check";
832+
// Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores.
833+
long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index;
834+
UNSAFE.putByte(val, address , (byte)(c1));
835+
UNSAFE.putByte(val, address + 1, (byte)(c2));
836+
UNSAFE.putByte(val, address + 2, (byte)(c3));
837+
UNSAFE.putByte(val, address + 3, (byte)(c4));
838+
}
839+
840+
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) {
841+
assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check";
842+
// Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores.
843+
long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index;
844+
UNSAFE.putByte(val, address , (byte)(c1));
845+
UNSAFE.putByte(val, address + 1, (byte)(c2));
846+
UNSAFE.putByte(val, address + 2, (byte)(c3));
847+
UNSAFE.putByte(val, address + 3, (byte)(c4));
848+
UNSAFE.putByte(val, address + 4, (byte)(c5));
849+
}
850+
827851
public static void putChar(byte[] val, int index, int c) {
828852
//assert (canEncode(c));
829853
val[index] = (byte)(c);

‎src/java.base/share/classes/java/lang/StringUTF16.java

+14-22
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import static java.lang.String.LATIN1;
4444

4545
final class StringUTF16 {
46-
4746
// Return a new byte array for a UTF16-coded string for len chars
4847
// Throw an exception if out of range
4948
public static byte[] newBytesFor(int len) {
@@ -1548,27 +1547,20 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) {
15481547
return true;
15491548
}
15501549

1551-
public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
1552-
int end = i + 4;
1553-
checkBoundsBeginEnd(i, end, value);
1554-
putChar(value, i++, c1);
1555-
putChar(value, i++, c2);
1556-
putChar(value, i++, c3);
1557-
putChar(value, i++, c4);
1558-
assert(i == end);
1559-
return end;
1560-
}
1561-
1562-
public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
1563-
int end = i + 5;
1564-
checkBoundsBeginEnd(i, end, value);
1565-
putChar(value, i++, c1);
1566-
putChar(value, i++, c2);
1567-
putChar(value, i++, c3);
1568-
putChar(value, i++, c4);
1569-
putChar(value, i++, c5);
1570-
assert(i == end);
1571-
return end;
1550+
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) {
1551+
assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check";
1552+
putChar(val, index , c1);
1553+
putChar(val, index + 1, c2);
1554+
putChar(val, index + 2, c3);
1555+
putChar(val, index + 3, c4);
1556+
}
1557+
1558+
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) {
1559+
putChar(val, index , c1);
1560+
putChar(val, index + 1, c2);
1561+
putChar(val, index + 2, c3);
1562+
putChar(val, index + 3, c4);
1563+
putChar(val, index + 4, c5);
15721564
}
15731565

15741566
public static char charAt(byte[] value, int index) {

‎test/hotspot/jtreg/compiler/patches/java.base/java/lang/Helper.java

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -133,11 +133,17 @@ public static boolean contentEquals(byte[] value, CharSequence cs, int len) {
133133
}
134134

135135
public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
136-
return StringUTF16.putCharsAt(value, i, c1, c2, c3, c4);
136+
int end = i + 4;
137+
StringUTF16.checkBoundsBeginEnd(i, end, value);
138+
StringUTF16.putCharsAt(value, i, c1, c2, c3, c4);
139+
return end;
137140
}
138141

139142
public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
140-
return StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5);
143+
int end = i + 5;
144+
StringUTF16.checkBoundsBeginEnd(i, end, value);
145+
StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5);
146+
return end;
141147
}
142148

143149
public static char charAt(byte[] value, int index) {

‎test/micro/org/openjdk/bench/java/lang/StringBuilders.java

+60-11
Original file line numberDiff line numberDiff line change
@@ -226,17 +226,66 @@ public String toStringCharWithInt8() {
226226

227227

228228
@Benchmark
229-
public String toStringCharWithBool8() {
230-
StringBuilder result = new StringBuilder();
231-
result.append(true);
232-
result.append(false);
233-
result.append(true);
234-
result.append(true);
235-
result.append(false);
236-
result.append(true);
237-
result.append(false);
238-
result.append(false);
239-
return result.toString();
229+
public int appendWithBool8Latin1() {
230+
StringBuilder buf = sbLatin1;
231+
buf.setLength(0);
232+
buf.append(true);
233+
buf.append(false);
234+
buf.append(true);
235+
buf.append(true);
236+
buf.append(false);
237+
buf.append(true);
238+
buf.append(false);
239+
buf.append(false);
240+
return buf.length();
241+
}
242+
243+
244+
@Benchmark
245+
public int appendWithBool8Utf16() {
246+
StringBuilder buf = sbUtf16;
247+
buf.setLength(0);
248+
buf.append(true);
249+
buf.append(false);
250+
buf.append(true);
251+
buf.append(true);
252+
buf.append(false);
253+
buf.append(true);
254+
buf.append(false);
255+
buf.append(false);
256+
return buf.length();
257+
}
258+
259+
260+
@Benchmark
261+
public int appendWithNull8Latin1() {
262+
StringBuilder buf = sbLatin1;
263+
buf.setLength(0);
264+
buf.append((String) null);
265+
buf.append((String) null);
266+
buf.append((String) null);
267+
buf.append((String) null);
268+
buf.append((String) null);
269+
buf.append((String) null);
270+
buf.append((String) null);
271+
buf.append((String) null);
272+
return buf.length();
273+
}
274+
275+
276+
@Benchmark
277+
public int appendWithNull8Utf16() {
278+
StringBuilder buf = sbUtf16;
279+
buf.setLength(0);
280+
buf.append((String) null);
281+
buf.append((String) null);
282+
buf.append((String) null);
283+
buf.append((String) null);
284+
buf.append((String) null);
285+
buf.append((String) null);
286+
buf.append((String) null);
287+
buf.append((String) null);
288+
return buf.length();
240289
}
241290

242291

0 commit comments

Comments
 (0)
Please sign in to comment.