< prev index next >

src/java.base/share/classes/java/lang/StringConcatHelper.java

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.  Oracle designates this

@@ -23,13 +23,10 @@
  * questions.
  */
 
 package java.lang;
 
-import jdk.internal.misc.Unsafe;
-import jdk.internal.vm.annotation.ForceInline;
-
 /**
  * Helper for string concatenation. These methods are mostly looked up with private lookups
  * from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle}
  * combinators there.
  */

@@ -39,101 +36,92 @@
         // no instantiation
     }
 
     /**
      * 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
+     * @param lengthCoder String length and coder
+     * @return lengthCoder
      */
     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
+     * @param current current length
+     * @param value   value to mix in
+     * @return new length and coder
      */
-    static long mix(long lengthCoder, boolean value) {
-        return checkOverflow(lengthCoder + (value ? 4 : 5));
+    static long mix(long current, boolean value) {
+        return checkOverflow(current + (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
+     * @param current current length
+     * @param value   value to mix in
+     * @return new length and coder
      */
-    static long mix(long lengthCoder, byte value) {
-        return mix(lengthCoder, (int)value);
+    static long mix(long current, byte value) {
+        return mix(current, (int)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
+     * @param current current length
+     * @param value   value to mix in
+     * @return new length and coder
      */
-    static long mix(long lengthCoder, char value) {
-        return checkOverflow(lengthCoder + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16);
+    static long mix(long current, char value) {
+        return checkOverflow(current + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16);
     }
 
     /**
      * 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
+     * @param current current length
+     * @param value   value to mix in
+     * @return new length and coder
      */
-    static long mix(long lengthCoder, short value) {
-        return mix(lengthCoder, (int)value);
+    static long mix(long current, short value) {
+        return mix(current, (int)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
+     * @param current current length
+     * @param value   value to mix in
+     * @return new length and coder
      */
-    static long mix(long lengthCoder, int value) {
-        return checkOverflow(lengthCoder + Integer.stringSize(value));
+    static long mix(long current, int value) {
+        return checkOverflow(current + Integer.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
+     * @param current current length
+     * @param value   value to mix in
+     * @return new length and coder
      */
-    static long mix(long lengthCoder, long value) {
-        return checkOverflow(lengthCoder + Long.stringSize(value));
+    static long mix(long current, long value) {
+        return checkOverflow(current + Long.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
+     * @param current current length
+     * @param value   value to mix in
+     * @return new length and coder
      */
-    static long mix(long lengthCoder, String value) {
-        lengthCoder += value.length();
+    static long mix(long current, String value) {
+        current += value.length();
         if (value.coder() == String.UTF16) {
-            lengthCoder |= UTF16;
+            current |= UTF16;
         }
-        return checkOverflow(lengthCoder);
+        return checkOverflow(current);
     }
 
     /**
      * Prepends the stringly representation of boolean value into buffer,
      * given the coder and final index. Index is measured in chars, not in bytes!

@@ -142,11 +130,11 @@
      *                   into higher bits.
      * @param buf        buffer to append to
      * @param value      boolean value to encode
      * @return           updated index (coder value retained)
      */
-    private static long prepend(long indexCoder, byte[] buf, boolean value) {
+    static long prepend(long indexCoder, byte[] buf, boolean value) {
         int index = (int)indexCoder;
         if (indexCoder < UTF16) {
             if (value) {
                 buf[--index] = 'e';
                 buf[--index] = 'u';

@@ -176,45 +164,21 @@
             return index | UTF16;
         }
     }
 
     /**
-     * Prepends constant and the stringly representation of value into buffer,
+     * Prepends the stringly representation of byte 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 prefix     a constant to prepend before value
-     * @param value      boolean value to encode
-     * @param suffix     a constant to prepend after value
+     * @param value      byte value to encode
      * @return           updated index (coder value retained)
      */
-    static long prepend(long indexCoder, byte[] buf, String prefix, boolean value, String suffix) {
-        if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
-        indexCoder = prepend(indexCoder, buf, value);
-        if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
-        return indexCoder;
-    }
-
-    /**
-     * 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 prefix     a constant to prepend before value
-     * @param value      boolean value to encode
-     * @param suffix     a constant to prepend after value
-     * @return           updated index (coder value retained)
-     */
-    static long prepend(long indexCoder, byte[] buf, String prefix, byte value, String suffix) {
-        if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
-        indexCoder = prepend(indexCoder, buf, (int)value);
-        if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
-        return indexCoder;
+    static long prepend(long indexCoder, byte[] buf, byte value) {
+        return prepend(indexCoder, buf, (int)value);
     }
 
     /**
      * Prepends the stringly representation of char value into buffer,
      * given the coder and final index. Index is measured in chars, not in bytes!

@@ -223,55 +187,31 @@
      *                   into higher bits.
      * @param buf        buffer to append to
      * @param value      char value to encode
      * @return           updated index (coder value retained)
      */
-    private static long prepend(long indexCoder, byte[] buf, char value) {
+    static long prepend(long indexCoder, byte[] buf, char value) {
         if (indexCoder < UTF16) {
             buf[(int)(--indexCoder)] = (byte) (value & 0xFF);
         } else {
             StringUTF16.putChar(buf, (int)(--indexCoder), value);
         }
         return indexCoder;
     }
 
     /**
-     * Prepends constant and the stringly representation of value into buffer,
+     * Prepends the stringly representation of short 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 prefix     a constant to prepend before value
-     * @param value      boolean value to encode
-     * @param suffix     a constant to prepend after value
+     * @param value      short value to encode
      * @return           updated index (coder value retained)
      */
-    static long prepend(long indexCoder, byte[] buf, String prefix, char value, String suffix) {
-        if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
-        indexCoder = prepend(indexCoder, buf, value);
-        if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
-        return indexCoder;
-    }
-
-    /**
-     * 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 prefix     a constant to prepend before value
-     * @param value      boolean value to encode
-     * @param suffix     a constant to prepend after value
-     * @return           updated index (coder value retained)
-     */
-    static long prepend(long indexCoder, byte[] buf, String prefix, short value, String suffix) {
-        if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
-        indexCoder = prepend(indexCoder, buf, (int)value);
-        if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
-        return indexCoder;
+    static long prepend(long indexCoder, byte[] buf, short value) {
+        return prepend(indexCoder, buf, (int)value);
     }
 
     /**
      * Prepends the stringly representation of integer value into buffer,
      * given the coder and final index. Index is measured in chars, not in bytes!

@@ -280,114 +220,57 @@
      *                   into higher bits.
      * @param buf        buffer to append to
      * @param value      integer value to encode
      * @return           updated index (coder value retained)
      */
-    private static long prepend(long indexCoder, byte[] buf, int value) {
+    static long prepend(long indexCoder, byte[] buf, int value) {
         if (indexCoder < UTF16) {
             return Integer.getChars(value, (int)indexCoder, buf);
         } else {
             return StringUTF16.getChars(value, (int)indexCoder, buf) | 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 prefix     a constant to prepend before value
-     * @param value      boolean value to encode
-     * @param suffix     a constant to prepend after value
-     * @return           updated index (coder value retained)
-     */
-    static long prepend(long indexCoder, byte[] buf, String prefix, int value, String suffix) {
-        if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
-        indexCoder = prepend(indexCoder, buf, value);
-        if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
-        return indexCoder;
-    }
-
-    /**
      * Prepends the stringly representation of long 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
      * @return           updated index (coder value retained)
      */
-    private static long prepend(long indexCoder, byte[] buf, long value) {
+    static long prepend(long indexCoder, byte[] buf, long value) {
         if (indexCoder < UTF16) {
             return Long.getChars(value, (int)indexCoder, buf);
         } else {
             return StringUTF16.getChars(value, (int)indexCoder, buf) | 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 prefix     a constant to prepend before value
-     * @param value      boolean value to encode
-     * @param suffix     a constant to prepend after value
-     * @return           updated index (coder value retained)
-     */
-    static long prepend(long indexCoder, byte[] buf, String prefix, long value, String suffix) {
-        if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
-        indexCoder = prepend(indexCoder, buf, value);
-        if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
-        return indexCoder;
-    }
-
-    /**
      * Prepends the stringly representation of String 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      String value to encode
      * @return           updated index (coder value retained)
      */
-    private static long prepend(long indexCoder, byte[] buf, String value) {
+    static long prepend(long indexCoder, byte[] buf, String value) {
         indexCoder -= value.length();
         if (indexCoder < UTF16) {
             value.getBytes(buf, (int)indexCoder, String.LATIN1);
         } else {
             value.getBytes(buf, (int)indexCoder, String.UTF16);
         }
         return indexCoder;
     }
 
     /**
-     * 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 prefix     a constant to prepend before value
-     * @param value      boolean value to encode
-     * @param suffix     a constant to prepend after value
-     * @return           updated index (coder value retained)
-     */
-    static long prepend(long indexCoder, byte[] buf, String prefix, String value, String suffix) {
-        if (suffix != null) indexCoder = prepend(indexCoder, buf, suffix);
-        indexCoder = prepend(indexCoder, buf, value);
-        if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix);
-        return indexCoder;
-    }
-
-    /**
      * 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
      */

@@ -400,66 +283,14 @@
         } 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
-     * {@code java.lang.invoke.StringConcatFactory$MethodHandleInlineCopyStrategy}
-     * for two Object arguments.
-     *
-     * @param first         first argument
-     * @param second        second argument
-     * @return String       resulting string
-     */
-    @ForceInline
-    static String simpleConcat(Object first, Object second) {
-        String s1 = stringOf(first);
-        String s2 = stringOf(second);
-        // start "mixing" in length and coder or arguments, order is not
-        // important
-        long indexCoder = mix(initialCoder(), s2);
-        indexCoder = mix(indexCoder, s1);
-        byte[] buf = newArray(indexCoder);
-        // prepend each argument in reverse order, since we prepending
-        // from the end of the byte array
-        indexCoder = prepend(indexCoder, buf, s2);
-        indexCoder = prepend(indexCoder, buf, s1);
-        return newString(buf, indexCoder);
-    }
-
-    /**
-     * We need some additional conversion for Objects in general, because
-     * {@code String.valueOf(Object)} may return null. String conversion rules
-     * in Java state we need to produce "null" String in this case, so we
-     * provide a customized version that deals with this problematic corner case.
-     */
-    static String stringOf(Object value) {
-        String s;
-        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();
-
-    /**
-     * 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;
-        return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder);
-    }
-
     /**
      * Provides the initial coder for the String.
      * @return initial coder, adjusted into the upper half
      */
     static long initialCoder() {
< prev index next >