diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index fd9dcf60e54..b40f6274412 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -830,9 +830,9 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence int spaceNeeded = count + DecimalDigits.stringSize(i); ensureCapacityInternal(spaceNeeded); if (isLatin1()) { - DecimalDigits.getCharsLatin1(i, spaceNeeded, value); + StringLatin1.getChars(i, spaceNeeded, value); } else { - DecimalDigits.getCharsUTF16(i, spaceNeeded, value); + StringUTF16.getChars(i, count, spaceNeeded, value); } this.count = spaceNeeded; return this; @@ -855,9 +855,9 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence int spaceNeeded = count + DecimalDigits.stringSize(l); ensureCapacityInternal(spaceNeeded); if (isLatin1()) { - DecimalDigits.getCharsLatin1(l, spaceNeeded, value); + StringLatin1.getChars(l, spaceNeeded, value); } else { - DecimalDigits.getCharsUTF16(l, spaceNeeded, value); + StringUTF16.getChars(l, count, spaceNeeded, value); } this.count = spaceNeeded; return this; diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 5f73d61e5d4..e666e977c61 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -432,11 +432,11 @@ public final class Integer extends Number int size = DecimalDigits.stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; - DecimalDigits.getCharsLatin1(i, size, buf); + StringLatin1.getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; - DecimalDigits.getCharsUTF16(i, size, buf); + StringUTF16.getChars(i, size, buf); return new String(buf, UTF16); } } diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 7df9ddfb270..8c083b3ec84 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -462,11 +462,11 @@ public final class Long extends Number int size = DecimalDigits.stringSize(i); if (COMPACT_STRINGS) { byte[] buf = new byte[size]; - DecimalDigits.getCharsLatin1(i, size, buf); + StringLatin1.getChars(i, size, buf); return new String(buf, LATIN1); } else { byte[] buf = new byte[size * 2]; - DecimalDigits.getCharsUTF16(i, size, buf); + StringUTF16.getChars(i, size, buf); return new String(buf, UTF16); } } diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index 632fe0f58b5..b635d0dee0f 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -298,12 +298,12 @@ final class StringConcatHelper { static long prepend(long indexCoder, byte[] buf, int value, String prefix) { int index = (int)indexCoder; if (indexCoder < UTF16) { - index = DecimalDigits.getCharsLatin1(value, index, buf); + index = StringLatin1.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.LATIN1); return index; } else { - index = DecimalDigits.getCharsUTF16(value, index, buf); + index = StringUTF16.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.UTF16); return index | UTF16; @@ -324,12 +324,12 @@ final class StringConcatHelper { static long prepend(long indexCoder, byte[] buf, long value, String prefix) { int index = (int)indexCoder; if (indexCoder < UTF16) { - index = DecimalDigits.getCharsLatin1(value, index, buf); + index = StringLatin1.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.LATIN1); return index; } else { - index = DecimalDigits.getCharsUTF16(value, index, buf); + index = StringUTF16.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.UTF16); return index | UTF16; @@ -682,11 +682,11 @@ final class StringConcatHelper { */ static int prepend(int index, byte coder, byte[] buf, int value, String prefix) { if (coder == String.LATIN1) { - index = DecimalDigits.getCharsLatin1(value, index, buf); + index = StringLatin1.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.LATIN1); } else { - index = DecimalDigits.getCharsUTF16(value, index, buf); + index = StringUTF16.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.UTF16); } @@ -706,11 +706,11 @@ final class StringConcatHelper { */ static int prepend(int index, byte coder, byte[] buf, long value, String prefix) { if (coder == String.LATIN1) { - index = DecimalDigits.getCharsLatin1(value, index, buf); + index = StringLatin1.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.LATIN1); } else { - index = DecimalDigits.getCharsUTF16(value, index, buf); + index = StringUTF16.getChars(value, index, buf); index -= prefix.length(); prefix.getBytes(buf, index, String.UTF16); } diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index abe42c2c7c7..c12b8afc21f 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -34,6 +34,7 @@ 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; import static java.lang.String.LATIN1; @@ -85,6 +86,120 @@ final class StringLatin1 { 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) { + // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. + int q; + int charPos = index; + + boolean negative = i < 0; + if (!negative) { + i = -i; + } + + // Generate two digits per iteration + while (i <= -100) { + q = i / 100; + charPos -= 2; + writeDigitPair(buf, charPos, (q * 100) - i); + i = q; + } + + // We know there are at most two digits left at this point. + if (i < -9) { + charPos -= 2; + writeDigitPair(buf, charPos, -i); + } 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) { + // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. + 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; + writeDigitPair(buf, charPos, (int)((q * 100) - i)); + i = q; + } + + // Get 2 digits/iteration using ints + int q2; + int i2 = (int)i; + while (i2 <= -100) { + q2 = i2 / 100; + charPos -= 2; + writeDigitPair(buf, charPos, (q2 * 100) - i2); + i2 = q2; + } + + // We know there are at most two digits left at this point. + if (i2 < -9) { + charPos -= 2; + writeDigitPair(buf, charPos, -i2); + } else { + buf[--charPos] = (byte)('0' - i2); + } + + if (negative) { + buf[--charPos] = (byte)'-'; + } + return charPos; + } + + private static void writeDigitPair(byte[] buf, int charPos, int value) { + short pair = DecimalDigits.digitPair(value); + buf[charPos] = (byte)(pair); + buf[charPos + 1] = (byte)(pair >> 8); + } + 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 a1dcca8ffad..f04b991827f 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -35,6 +35,7 @@ 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.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -1512,6 +1513,20 @@ final class StringUTF16 { return codePointCount(val, beginIndex, endIndex, true /* checked */); } + public static int getChars(int i, int begin, int end, byte[] value) { + checkBoundsBeginEnd(begin, end, value); + int pos = getChars(i, end, value); + assert begin == pos; + return pos; + } + + public static int getChars(long l, int begin, int end, byte[] value) { + checkBoundsBeginEnd(begin, end, value); + int pos = getChars(l, end, value); + assert begin == pos; + return pos; + } + public static boolean contentEquals(byte[] v1, byte[] v2, int len) { checkBoundsOffCount(0, len, v2); for (int i = 0; i < len; i++) { @@ -1647,6 +1662,109 @@ final class StringUTF16 { static final int MAX_LENGTH = Integer.MAX_VALUE >> 1; + // Used by trusted callers. Assumes all necessary bounds checks have + // been done by the caller. + + /** + * This is a variant of {@link StringLatin1#getChars(int, int, byte[])}, but for + * UTF-16 coder. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, UTF16-coded. + * @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; + + boolean negative = (i < 0); + if (!negative) { + i = -i; + } + + // Get 2 digits/iteration using ints + while (i <= -100) { + q = i / 100; + r = (q * 100) - i; + i = q; + charPos -= 2; + putPair(buf, charPos, r); + } + + // We know there are at most two digits left at this point. + if (i < -9) { + charPos -= 2; + putPair(buf, charPos, -i); + } else { + putChar(buf, --charPos, '0' - i); + } + + if (negative) { + putChar(buf, --charPos, '-'); + } + return charPos; + } + + /** + * This is a variant of {@link StringLatin1#getChars(long, int, byte[])}, but for + * UTF-16 coder. + * + * @param i value to convert + * @param index next index, after the least significant digit + * @param buf target buffer, UTF16-coded. + * @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; + + 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; + putPair(buf, charPos, (int)((q * 100) - i)); + i = q; + } + + // Get 2 digits/iteration using ints + int q2; + int i2 = (int)i; + while (i2 <= -100) { + q2 = i2 / 100; + charPos -= 2; + putPair(buf, charPos, (q2 * 100) - i2); + i2 = q2; + } + + // We know there are at most two digits left at this point. + if (i2 < -9) { + charPos -= 2; + putPair(buf, charPos, -i2); + } else { + putChar(buf, --charPos, '0' - i2); + } + + if (negative) { + putChar(buf, --charPos, '-'); + } + return charPos; + } + + private static void putPair(byte[] buf, int charPos, int v) { + int packed = (int) DecimalDigits.digitPair(v); + putChar(buf, charPos, packed & 0xFF); + putChar(buf, charPos + 1, packed >> 8); + } + // End of trusted methods. + public static void checkIndex(int off, byte[] val) { String.checkIndex(off, length(val)); } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 451ed8e6bfc..5b04bca4f44 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2648,6 +2648,14 @@ public final class System { return str.coder(); } + public int getCharsLatin1(long i, int index, byte[] buf) { + return StringLatin1.getChars(i, index, buf); + } + + public int getCharsUTF16(long i, int index, byte[] buf) { + return StringUTF16.getChars(i, index, buf); + } + public String join(String prefix, String suffix, String delimiter, String[] elements, int size) { return String.join(prefix, suffix, delimiter, elements, size); } diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index b00970963b6..abd49aa69bc 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -35,15 +35,9 @@ import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamException; import java.io.StreamCorruptedException; -import java.nio.charset.CharacterCodingException; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Objects; -import jdk.internal.access.JavaLangAccess; -import jdk.internal.access.SharedSecrets; -import jdk.internal.util.DecimalDigits; - /** * Immutable, arbitrary-precision signed decimal numbers. A {@code * BigDecimal} consists of an arbitrary precision integer @@ -334,8 +328,6 @@ import jdk.internal.util.DecimalDigits; * @since 1.1 */ public class BigDecimal extends Number implements Comparable { - private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); - /* * Let l = log_2(10). * Then, L < l < L + ulp(L) / 2, that is, L = roundTiesToEven(l). @@ -4172,6 +4164,103 @@ public class BigDecimal extends Number implements Comparable { return BigDecimal.valueOf(1, this.scale(), 1); } + // Private class to build a string representation for BigDecimal object. The + // StringBuilder field acts as a buffer to hold the temporary representation + // of BigDecimal. The cmpCharArray holds all the characters for the compact + // representation of BigDecimal (except for '-' sign' if it is negative) if + // its intCompact field is not INFLATED. + static class StringBuilderHelper { + final StringBuilder sb; // Placeholder for BigDecimal string + final char[] cmpCharArray; // character array to place the intCompact + + StringBuilderHelper() { + sb = new StringBuilder(32); + // All non negative longs can be made to fit into 19 character array. + cmpCharArray = new char[19]; + } + + // Accessors. + StringBuilder getStringBuilder() { + sb.setLength(0); + return sb; + } + + char[] getCompactCharArray() { + return cmpCharArray; + } + + /** + * Places characters representing the intCompact in {@code long} into + * cmpCharArray and returns the offset to the array where the + * representation starts. + * + * @param intCompact the number to put into the cmpCharArray. + * @return offset to the array where the representation starts. + * Note: intCompact must be greater or equal to zero. + */ + int putIntCompact(long intCompact) { + assert intCompact >= 0; + + long q; + int r; + // since we start from the least significant digit, charPos points to + // the last character in cmpCharArray. + int charPos = cmpCharArray.length; + + // Get 2 digits/iteration using longs until quotient fits into an int + while (intCompact > Integer.MAX_VALUE) { + q = intCompact / 100; + r = (int)(intCompact - q * 100); + intCompact = q; + cmpCharArray[--charPos] = DIGIT_ONES[r]; + cmpCharArray[--charPos] = DIGIT_TENS[r]; + } + + // Get 2 digits/iteration using ints when i2 >= 100 + int q2; + int i2 = (int)intCompact; + while (i2 >= 100) { + q2 = i2 / 100; + r = i2 - q2 * 100; + i2 = q2; + cmpCharArray[--charPos] = DIGIT_ONES[r]; + cmpCharArray[--charPos] = DIGIT_TENS[r]; + } + + cmpCharArray[--charPos] = DIGIT_ONES[i2]; + if (i2 >= 10) + cmpCharArray[--charPos] = DIGIT_TENS[i2]; + + return charPos; + } + + static final char[] DIGIT_TENS = { + '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 char[] DIGIT_ONES = { + '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', + }; + } + /** * Lay out this {@code BigDecimal} into a {@code char[]} array. * The Java 1.2 equivalent to this was called {@code getValueString}. @@ -4182,8 +4271,6 @@ public class BigDecimal extends Number implements Comparable { * {@code BigDecimal} */ private String layoutChars(boolean sci) { - long intCompact = this.intCompact; - int scale = this.scale; if (scale == 0) // zero scale is trivial return (intCompact != INFLATED) ? Long.toString(intCompact): @@ -4193,24 +4280,18 @@ public class BigDecimal extends Number implements Comparable { // currency fast path int lowInt = (int)intCompact % 100; int highInt = (int)intCompact / 100; - int highIntSize = DecimalDigits.stringSize(highInt); - byte[] buf = new byte[highIntSize + 3]; - DecimalDigits.putPairLatin1(buf, highIntSize + 1, lowInt); - buf[highIntSize] = '.'; - DecimalDigits.getCharsLatin1(highInt, highIntSize, buf); - try { - return JLA.newStringNoRepl(buf, StandardCharsets.ISO_8859_1); - } catch (CharacterCodingException cce) { - throw new AssertionError(cce); - } + return (Integer.toString(highInt) + '.' + + StringBuilderHelper.DIGIT_TENS[lowInt] + + StringBuilderHelper.DIGIT_ONES[lowInt]) ; } + StringBuilderHelper sbHelper = new StringBuilderHelper(); char[] coeff; int offset; // offset is the starting index for coeff array // Get the significand as an absolute value if (intCompact != INFLATED) { - coeff = new char[19]; - offset = DecimalDigits.getChars(Math.abs(intCompact), coeff.length, coeff); + offset = sbHelper.putIntCompact(Math.abs(intCompact)); + coeff = sbHelper.getCompactCharArray(); } else { offset = 0; coeff = intVal.abs().toString().toCharArray(); @@ -4220,7 +4301,7 @@ public class BigDecimal extends Number implements Comparable { // If E-notation is needed, length will be: +1 if negative, +1 // if '.' needed, +2 for "E+", + up to 10 for adjusted exponent. // Otherwise it could have +1 if negative, plus leading "0.00000" - StringBuilder buf = new StringBuilder(32);; + StringBuilder buf = sbHelper.getStringBuilder(); if (signum() < 0) // prefix '-' if negative buf.append('-'); int coeffLen = coeff.length - offset; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index ecfdbd28095..0436cbb314f 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -487,6 +487,10 @@ public interface JavaLangAccess { */ Object classData(Class c); + int getCharsLatin1(long i, int index, byte[] buf); + + int getCharsUTF16(long i, int index, byte[] buf); + /** * Returns the {@link NativeLibraries} object associated with the provided class loader. * This is used by {@link SymbolLookup#loaderLookup()}. diff --git a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java index 75e67e3f9cc..83438e59b82 100644 --- a/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java +++ b/src/java.base/share/classes/jdk/internal/util/DecimalDigits.java @@ -25,18 +25,14 @@ package jdk.internal.util; -import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.Stable; -import static jdk.internal.misc.Unsafe.ARRAY_BYTE_BASE_OFFSET; - /** * Digits class for decimal digits. * * @since 21 */ public final class DecimalDigits { - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); /** * Each element of the array represents the packaging of two ascii characters based on little endian:

@@ -80,6 +76,15 @@ public final class DecimalDigits { private DecimalDigits() { } + /** + * For values from 0 to 99 return a short encoding a pair of ASCII-encoded digit characters in little-endian + * @param i value to convert + * @return a short encoding a pair of ASCII-encoded digit characters + */ + public static short digitPair(int i) { + return DIGITS[i]; + } + /** * Returns the string representation size for a given int value. * @@ -131,306 +136,4 @@ public final class DecimalDigits { } return 19 + d; } - - /** - * 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 - */ - public static int getCharsLatin1(int i, int index, byte[] buf) { - // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. - int q; - int charPos = index; - - boolean negative = i < 0; - if (!negative) { - i = -i; - } - - // Generate two digits per iteration - while (i <= -100) { - q = i / 100; - charPos -= 2; - putPairLatin1(buf, charPos, (q * 100) - i); - i = q; - } - - // We know there are at most two digits left at this point. - if (i < -9) { - charPos -= 2; - putPairLatin1(buf, charPos, -i); - } else { - putCharLatin1(buf, --charPos, '0' - i); - } - - if (negative) { - putCharLatin1(buf, --charPos, '-'); - } - 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 - */ - public static int getCharsLatin1(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; - - 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; - putPairLatin1(buf, charPos, (int)((q * 100) - i)); - i = q; - } - - // Get 2 digits/iteration using ints - int q2; - int i2 = (int)i; - while (i2 <= -100) { - q2 = i2 / 100; - charPos -= 2; - putPairLatin1(buf, charPos, (q2 * 100) - i2); - i2 = q2; - } - - // We know there are at most two digits left at this point. - if (i2 < -9) { - charPos -= 2; - putPairLatin1(buf, charPos, -i2); - } else { - putCharLatin1(buf, --charPos, '0' - i2); - } - - if (negative) { - putCharLatin1(buf, --charPos, '-'); - } - return charPos; - } - - - /** - * This is a variant of {@link DecimalDigits#getCharsLatin1(int, int, byte[])}, but for - * UTF-16 coder. - * - * @param i value to convert - * @param index next index, after the least significant digit - * @param buf target buffer, UTF16-coded. - * @return index of the most significant digit or minus sign, if present - */ - public static int getCharsUTF16(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; - - boolean negative = (i < 0); - if (!negative) { - i = -i; - } - - // Get 2 digits/iteration using ints - while (i <= -100) { - q = i / 100; - r = (q * 100) - i; - i = q; - charPos -= 2; - putPairUTF16(buf, charPos, r); - } - - // We know there are at most two digits left at this point. - if (i < -9) { - charPos -= 2; - putPairUTF16(buf, charPos, -i); - } else { - putCharUTF16(buf, --charPos, '0' - i); - } - - if (negative) { - putCharUTF16(buf, --charPos, '-'); - } - return charPos; - } - - - /** - * This is a variant of {@link DecimalDigits#getCharsLatin1(long, int, byte[])}, but for - * UTF-16 coder. - * - * @param i value to convert - * @param index next index, after the least significant digit - * @param buf target buffer, UTF16-coded. - * @return index of the most significant digit or minus sign, if present - */ - public static int getCharsUTF16(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; - - 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; - putPairUTF16(buf, charPos, (int)((q * 100) - i)); - i = q; - } - - // Get 2 digits/iteration using ints - int q2; - int i2 = (int)i; - while (i2 <= -100) { - q2 = i2 / 100; - charPos -= 2; - putPairUTF16(buf, charPos, (q2 * 100) - i2); - i2 = q2; - } - - // We know there are at most two digits left at this point. - if (i2 < -9) { - charPos -= 2; - putPairUTF16(buf, charPos, -i2); - } else { - putCharUTF16(buf, --charPos, '0' - i2); - } - - if (negative) { - putCharUTF16(buf, --charPos, '-'); - } - return charPos; - } - - /** - * This is a variant of {@link DecimalDigits#getCharsUTF16(long, int, byte[])}, but for - * UTF-16 coder. - * - * @param i value to convert - * @param index next index, after the least significant digit - * @param buf target buffer, UTF16-coded. - * @return index of the most significant digit or minus sign, if present - */ - public static int getChars(long i, int index, char[] buf) { - // Used by trusted callers. Assumes all necessary bounds checks have been done by the caller. - 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; - putPair(buf, charPos, (int)((q * 100) - i)); - i = q; - } - - // Get 2 digits/iteration using ints - int q2; - int i2 = (int)i; - while (i2 <= -100) { - q2 = i2 / 100; - charPos -= 2; - putPair(buf, charPos, (q2 * 100) - i2); - i2 = q2; - } - - // We know there are at most two digits left at this point. - if (i2 < -9) { - charPos -= 2; - putPair(buf, charPos, -i2); - } else { - buf[--charPos] = (char) ('0' - i2); - } - - if (negative) { - buf[--charPos] = '-'; - } - return charPos; - } - - /** - * Insert the 2-chars integer into the buf as 2 decimal digit ASCII chars, - * only least significant 16 bits of {@code v} are used. - * @param buf byte buffer to copy into - * @param charPos insert point - * @param v to convert - */ - public static void putPair(char[] buf, int charPos, int v) { - int packed = DIGITS[v]; - buf[charPos ] = (char) (packed & 0xFF); - buf[charPos + 1] = (char) (packed >> 8); - } - - /** - * Insert the 2-bytes integer into the buf as 2 decimal digit ASCII bytes, - * only least significant 16 bits of {@code v} are used. - * @param buf byte buffer to copy into - * @param charPos insert point - * @param v to convert - */ - public static void putPairLatin1(byte[] buf, int charPos, int v) { - int packed = DIGITS[v]; - putCharLatin1(buf, charPos, packed & 0xFF); - putCharLatin1(buf, charPos + 1, packed >> 8); - } - - /** - * Insert the 2-chars integer into the buf as 2 decimal digit UTF16 bytes, - * only least significant 16 bits of {@code v} are used. - * @param buf byte buffer to copy into - * @param charPos insert point - * @param v to convert - */ - public static void putPairUTF16(byte[] buf, int charPos, int v) { - int packed = DIGITS[v]; - putCharUTF16(buf, charPos, packed & 0xFF); - putCharUTF16(buf, charPos + 1, packed >> 8); - } - - private static void putCharLatin1(byte[] buf, int charPos, int c) { - UNSAFE.putByte(buf, ARRAY_BYTE_BASE_OFFSET + charPos, (byte) c); - } - - private static void putCharUTF16(byte[] buf, int charPos, int c) { - UNSAFE.putChar(buf, ARRAY_BYTE_BASE_OFFSET + (charPos << 1), (char) c); - } } 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 a60354ec2fc..5ecc01aa2bc 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 @@ -23,8 +23,6 @@ package java.lang; -import jdk.internal.util.DecimalDigits; - /** * A helper class to get access to package-private members */ @@ -119,17 +117,11 @@ public class Helper { } public static int getChars(int i, int begin, int end, byte[] value) { - StringUTF16.checkBoundsBeginEnd(begin, end, value); - int pos = DecimalDigits.getCharsUTF16(i, end, value); - assert begin == pos; - return pos; + return StringUTF16.getChars(i, begin, end, value); } public static int getChars(long l, int begin, int end, byte[] value) { - StringUTF16.checkBoundsBeginEnd(begin, end, value); - int pos = DecimalDigits.getCharsUTF16(l, end, value); - assert begin == pos; - return pos; + return StringUTF16.getChars(l, begin, end, value); } public static boolean contentEquals(byte[] v1, byte[] v2, int len) { diff --git a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java index e41bd361ff5..ed5c0d30db8 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java +++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java @@ -54,8 +54,6 @@ public class StringBuilders { private StringBuilder sbLatin2; private StringBuilder sbUtf16; private StringBuilder sbUtf17; - private int[] intsArray; - private long[] longArray; @Setup public void setup() { @@ -71,13 +69,6 @@ public class StringBuilders { sbLatin2 = new StringBuilder("Latin1 string"); sbUtf16 = new StringBuilder("UTF-\uFF11\uFF16 string"); sbUtf17 = new StringBuilder("UTF-\uFF11\uFF16 string"); - int size = 16; - intsArray = new int[size]; - longArray = new long[size]; - for (int i = 0; i < longArray.length; i++) { - intsArray[i] = ((100 * i + i) << 24) + 4543 + i * 4; - longArray[i] = ((100L * i + i) << 32) + 4543 + i * 4L; - } } @Benchmark @@ -233,47 +224,6 @@ public class StringBuilders { return result.toString(); } - @Benchmark - public int appendWithIntLatin1() { - StringBuilder buf = sbLatin1; - buf.setLength(0); - for (long l : longArray) { - buf.append(l); - } - return buf.length(); - } - - @Benchmark - public int appendWithIntUtf16() { - StringBuilder buf = sbUtf16; - buf.setLength(0); - buf.setLength(0); - for (long l : longArray) { - buf.append(l); - } - return buf.length(); - } - - @Benchmark - public int appendWithLongLatin1() { - StringBuilder buf = sbLatin1; - buf.setLength(0); - for (long l : longArray) { - buf.append(l); - } - return buf.length(); - } - - @Benchmark - public int appendWithLongUtf16() { - StringBuilder buf = sbUtf16; - buf.setLength(0); - buf.setLength(0); - for (long l : longArray) { - buf.append(l); - } - return buf.length(); - } @Benchmark public int appendWithBool8Latin1() {