diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 24ead22e283..a18ac3250dc 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -3710,7 +3710,7 @@ public final class String if (len < 0L || (len <<= coder) != (int) len) { throw new OutOfMemoryError("Requested string length exceeds VM limit"); } - byte[] value = StringConcatHelper.newArray(len); + byte[] value = StringConcatHelper.newArray((int) len); int off = 0; prefix.getBytes(value, off, coder); off += prefix.length(); diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index a5f6abbfdf1..aeff494cabb 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -141,262 +141,6 @@ final class StringConcatHelper { // no instantiation } - /** - * Return the coder for the character. - * @param value character - * @return coder - */ - static long coder(char value) { - return StringLatin1.canEncode(value) ? LATIN1 : UTF16; - } - - /** - * Check for overflow, throw exception on overflow. - * - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @return the given parameter value, if valid - */ - private static long checkOverflow(long lengthCoder) { - if ((int)lengthCoder >= 0) { - return lengthCoder; - } - throw new OutOfMemoryError("Overflow: String length out of range"); - } - - /** - * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder - */ - static long mix(long lengthCoder, boolean value) { - return checkOverflow(lengthCoder + (value ? 4 : 5)); - } - - /** - * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder - */ - static long mix(long lengthCoder, char value) { - return checkOverflow(lengthCoder + 1) | coder(value); - } - - /** - * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder - */ - static long mix(long lengthCoder, int value) { - return checkOverflow(lengthCoder + DecimalDigits.stringSize(value)); - } - - /** - * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder - */ - static long mix(long lengthCoder, long value) { - return checkOverflow(lengthCoder + DecimalDigits.stringSize(value)); - } - - /** - * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder - */ - static long mix(long lengthCoder, String value) { - lengthCoder += value.length(); - if (!value.isLatin1()) { - lengthCoder |= UTF16; - } - return checkOverflow(lengthCoder); - } - - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value boolean value to encode - * @param prefix a constant to prepend before value - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) { - int index = (int)indexCoder; - if (indexCoder < UTF16) { - if (value) { - index -= 4; - buf[index] = 't'; - buf[index + 1] = 'r'; - buf[index + 2] = 'u'; - buf[index + 3] = 'e'; - } else { - index -= 5; - buf[index] = 'f'; - buf[index + 1] = 'a'; - buf[index + 2] = 'l'; - buf[index + 3] = 's'; - buf[index + 4] = 'e'; - } - index -= prefix.length(); - prefix.getBytes(buf, index, String.LATIN1); - return index; - } else { - if (value) { - index -= 4; - StringUTF16.putChar(buf, index, 't'); - StringUTF16.putChar(buf, index + 1, 'r'); - StringUTF16.putChar(buf, index + 2, 'u'); - StringUTF16.putChar(buf, index + 3, 'e'); - } else { - index -= 5; - StringUTF16.putChar(buf, index, 'f'); - StringUTF16.putChar(buf, index + 1, 'a'); - StringUTF16.putChar(buf, index + 2, 'l'); - StringUTF16.putChar(buf, index + 3, 's'); - StringUTF16.putChar(buf, index + 4, 'e'); - } - index -= prefix.length(); - prefix.getBytes(buf, index, String.UTF16); - return index | UTF16; - } - } - - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value char value to encode - * @param prefix a constant to prepend before value - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, char value, String prefix) { - int index = (int)indexCoder; - if (indexCoder < UTF16) { - buf[--index] = (byte) (value & 0xFF); - index -= prefix.length(); - prefix.getBytes(buf, index, String.LATIN1); - return index; - } else { - StringUTF16.putChar(buf, --index, value); - index -= prefix.length(); - prefix.getBytes(buf, index, String.UTF16); - return index | UTF16; - } - } - - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value int value to encode - * @param prefix a constant to prepend before value - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, int value, String prefix) { - int index = (int)indexCoder; - if (indexCoder < UTF16) { - index = DecimalDigits.uncheckedGetCharsLatin1(value, index, buf); - index -= prefix.length(); - prefix.getBytes(buf, index, String.LATIN1); - return index; - } else { - index = DecimalDigits.uncheckedGetCharsUTF16(value, index, buf); - index -= prefix.length(); - prefix.getBytes(buf, index, String.UTF16); - return index | UTF16; - } - } - - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value long value to encode - * @param prefix a constant to prepend before value - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, long value, String prefix) { - int index = (int)indexCoder; - if (indexCoder < UTF16) { - index = DecimalDigits.uncheckedGetCharsLatin1(value, index, buf); - index -= prefix.length(); - prefix.getBytes(buf, index, String.LATIN1); - return index; - } else { - index = DecimalDigits.uncheckedGetCharsUTF16(value, index, buf); - index -= prefix.length(); - prefix.getBytes(buf, index, String.UTF16); - return index | UTF16; - } - } - - /** - * Prepends constant and the stringly representation of value into buffer, - * given the coder and final index. Index is measured in chars, not in bytes! - * - * @param indexCoder final char index in the buffer, along with coder packed - * into higher bits. - * @param buf buffer to append to - * @param value boolean value to encode - * @param prefix a constant to prepend before value - * @return updated index (coder value retained) - */ - static long prepend(long indexCoder, byte[] buf, String value, String prefix) { - int index = ((int)indexCoder) - value.length(); - if (indexCoder < UTF16) { - value.getBytes(buf, index, String.LATIN1); - index -= prefix.length(); - prefix.getBytes(buf, index, String.LATIN1); - return index; - } else { - value.getBytes(buf, index, String.UTF16); - index -= prefix.length(); - prefix.getBytes(buf, index, String.UTF16); - return index | UTF16; - } - } - - /** - * Instantiates the String with given buffer and coder - * @param buf buffer to use - * @param indexCoder remaining index (should be zero) and coder - * @return String resulting string - */ - static String newString(byte[] buf, long indexCoder) { - // Use the private, non-copying constructor (unsafe!) - if (indexCoder == LATIN1) { - return new String(buf, String.LATIN1); - } else if (indexCoder == UTF16) { - return new String(buf, String.UTF16); - } else { - throw new InternalError("Storage is not completely initialized, " + - (int)indexCoder + " bytes left"); - } - } - /** * Perform a simple concatenation between two objects. Added for startup * performance, but also demonstrates the code that would be emitted by @@ -466,10 +210,6 @@ final class StringConcatHelper { return (value == null || (s = value.toString()) == null) ? "null" : s; } - private static final long LATIN1 = (long)String.LATIN1 << 32; - - private static final long UTF16 = (long)String.UTF16 << 32; - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); static String stringOf(float value) { @@ -530,41 +270,6 @@ final class StringConcatHelper { return checkOverflow(length + value.length()); } - /** - * Allocates an uninitialized byte array based on the length and coder - * information, then prepends the given suffix string at the end of the - * byte array before returning it. The calling code must adjust the - * indexCoder so that it's taken the coder of the suffix into account, but - * subtracted the length of the suffix. - * - * @param suffix - * @param indexCoder - * @return the newly allocated byte array - */ - @ForceInline - static byte[] newArrayWithSuffix(String suffix, long indexCoder) { - byte[] buf = newArray(indexCoder + suffix.length()); - if (indexCoder < UTF16) { - suffix.getBytes(buf, (int)indexCoder, String.LATIN1); - } else { - suffix.getBytes(buf, (int)indexCoder, String.UTF16); - } - return buf; - } - - /** - * Allocates an uninitialized byte array based on the length and coder information - * in indexCoder - * @param indexCoder - * @return the newly allocated byte array - */ - @ForceInline - static byte[] newArray(long indexCoder) { - byte coder = (byte)(indexCoder >> 32); - int index = ((int)indexCoder) << coder; - return newArray(index); - } - /** * Allocates an uninitialized byte array based on the length * @param length @@ -578,14 +283,6 @@ final class StringConcatHelper { return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, length); } - /** - * Provides the initial coder for the String. - * @return initial coder, adjusted into the upper half - */ - static long initialCoder() { - return String.COMPACT_STRINGS ? LATIN1 : UTF16; - } - static MethodHandle lookupStatic(String name, MethodType methodType) { try { return MethodHandles.lookup() @@ -603,7 +300,8 @@ final class StringConcatHelper { * subtracted the length of the suffix. * * @param suffix - * @param indexCoder + * @param index final char index in the buffer + * @param coder coder of the buffer * @return the newly allocated byte array */ @ForceInline diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index bb1775fbc6b..c88cf4ac797 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2185,18 +2185,6 @@ public final class System { return StringConcatHelper.lookupStatic(name, methodType); } - public long stringConcatInitialCoder() { - return StringConcatHelper.initialCoder(); - } - - public long stringConcatMix(long lengthCoder, String constant) { - return StringConcatHelper.mix(lengthCoder, constant); - } - - public long stringConcatMix(long lengthCoder, char value) { - return StringConcatHelper.mix(lengthCoder, value); - } - public Object uncheckedStringConcat1(String[] constants) { return new StringConcatHelper.Concat1(constants); } diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 1c7995c4ec7..733714b5786 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -37,7 +37,6 @@ import jdk.internal.util.ReferenceKey; import jdk.internal.util.ReferencedKeyMap; import jdk.internal.vm.annotation.AOTSafeClassInitializer; import jdk.internal.vm.annotation.Stable; -import sun.invoke.util.Wrapper; import java.lang.classfile.Annotation; import java.lang.classfile.ClassBuilder; @@ -119,14 +118,10 @@ import static java.lang.invoke.MethodType.methodType; */ @AOTSafeClassInitializer public final class StringConcatFactory { - private static final int HIGH_ARITY_THRESHOLD; private static final int CACHE_THRESHOLD; private static final int FORCE_INLINE_THRESHOLD; static { - String highArity = VM.getSavedProperty("java.lang.invoke.StringConcat.highArityThreshold"); - HIGH_ARITY_THRESHOLD = highArity != null ? Integer.parseInt(highArity) : 0; - String cacheThreshold = VM.getSavedProperty("java.lang.invoke.StringConcat.cacheThreshold"); CACHE_THRESHOLD = cacheThreshold != null ? Integer.parseInt(cacheThreshold) : 256; @@ -391,9 +386,6 @@ public final class StringConcatFactory { try { MethodHandle mh = makeSimpleConcat(concatType, constantStrings); - if (mh == null && concatType.parameterCount() <= HIGH_ARITY_THRESHOLD) { - mh = generateMHInlineCopy(concatType, constantStrings); - } if (mh == null) { mh = InlineHiddenClassStrategy.generate(lookup, concatType, constantStrings); @@ -518,385 +510,6 @@ public final class StringConcatFactory { return null; } - /** - *
This strategy replicates what StringBuilders are doing: it builds the
- * byte[] array on its own and passes that byte[] array to String
- * constructor. This strategy requires access to some private APIs in JDK,
- * most notably, the private String constructor that accepts byte[] arrays
- * without copying.
- */
- private static MethodHandle generateMHInlineCopy(MethodType mt, String[] constants) {
- int paramCount = mt.parameterCount();
- String suffix = constants[paramCount];
-
-
- // else... fall-through to slow-path
-
- // Create filters and obtain filtered parameter types. Filters would be used in the beginning
- // to convert the incoming arguments into the arguments we can process (e.g. Objects -> Strings).
- // The filtered argument type list is used all over in the combinators below.
-
- Class>[] ptypes = mt.erase().parameterArray();
- MethodHandle[] objFilters = null;
- MethodHandle[] floatFilters = null;
- MethodHandle[] doubleFilters = null;
- for (int i = 0; i < ptypes.length; i++) {
- Class> cl = ptypes[i];
- // Use int as the logical type for subword integral types
- // (byte and short). char and boolean require special
- // handling so don't change the logical type of those
- ptypes[i] = promoteToIntType(ptypes[i]);
- // Object, float and double will be eagerly transformed
- // into a (non-null) String as a first step after invocation.
- // Set up to use String as the logical type for such arguments
- // internally.
- if (cl == Object.class) {
- if (objFilters == null) {
- objFilters = new MethodHandle[ptypes.length];
- }
- objFilters[i] = objectStringifier();
- ptypes[i] = String.class;
- } else if (cl == float.class) {
- if (floatFilters == null) {
- floatFilters = new MethodHandle[ptypes.length];
- }
- floatFilters[i] = floatStringifier();
- ptypes[i] = String.class;
- } else if (cl == double.class) {
- if (doubleFilters == null) {
- doubleFilters = new MethodHandle[ptypes.length];
- }
- doubleFilters[i] = doubleStringifier();
- ptypes[i] = String.class;
- }
- }
-
- // Start building the combinator tree. The tree "starts" with (