8333893: Optimization for StringBuilder append boolean & null

Reviewed-by: liach
This commit is contained in:
Shaojin Wen 2024-11-05 15:05:33 +00:00
parent c33a8f52b6
commit 5890d9438b
5 changed files with 113 additions and 52 deletions

View File

@ -640,14 +640,11 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
val[count++] = 'n';
val[count++] = 'u';
val[count++] = 'l';
val[count++] = 'l';
StringLatin1.putCharsAt(val, count, 'n', 'u', 'l', '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;
}
@ -772,25 +769,18 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
byte[] val = this.value;
if (isLatin1()) {
if (b) {
val[count++] = 't';
val[count++] = 'r';
val[count++] = 'u';
val[count++] = 'e';
StringLatin1.putCharsAt(val, count, 't', 'r', 'u', 'e');
} else {
val[count++] = 'f';
val[count++] = 'a';
val[count++] = 'l';
val[count++] = 's';
val[count++] = 'e';
StringLatin1.putCharsAt(val, count, 'f', 'a', 'l', 's', '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 = count + (b ? 4 : 5);
return this;
}

View File

@ -32,6 +32,7 @@ import java.util.function.Consumer;
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;
@ -42,6 +43,8 @@ import static java.lang.String.checkIndex;
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);
@ -824,6 +827,27 @@ final class StringLatin1 {
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.
long address = Unsafe.ARRAY_BYTE_BASE_OFFSET + index;
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.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) {
//assert (canEncode(c));
val[index] = (byte)(c);

View File

@ -43,7 +43,6 @@ import static java.lang.String.UTF16;
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) {
@ -1548,27 +1547,20 @@ final class StringUTF16 {
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;
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";
putChar(val, index , c1);
putChar(val, index + 1, c2);
putChar(val, index + 2, c3);
putChar(val, index + 3, c4);
}
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;
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) {
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) {

View File

@ -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
@ -133,11 +133,17 @@ public class Helper {
}
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);
int end = i + 4;
StringUTF16.checkBoundsBeginEnd(i, end, value);
StringUTF16.putCharsAt(value, i, c1, c2, c3, c4);
return end;
}
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);
int end = i + 5;
StringUTF16.checkBoundsBeginEnd(i, end, value);
StringUTF16.putCharsAt(value, i, c1, c2, c3, c4, c5);
return end;
}
public static char charAt(byte[] value, int index) {

View File

@ -226,17 +226,66 @@ public class StringBuilders {
@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 appendWithBool8Latin1() {
StringBuilder buf = sbLatin1;
buf.setLength(0);
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 appendWithBool8Utf16() {
StringBuilder buf = sbUtf16;
buf.setLength(0);
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 appendWithNull8Latin1() {
StringBuilder buf = sbLatin1;
buf.setLength(0);
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 appendWithNull8Utf16() {
StringBuilder buf = sbUtf16;
buf.setLength(0);
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();
}