8221430: StringBuffer(CharSequence) constructor truncates when -XX:-CompactStrings specified
authorigerasim
Tue, 09 Apr 2019 16:32:22 -0700
changeset 54481 f847a42ddc01
parent 54480 625f49b603f0
child 54482 c914170817d4
child 54483 ac20c3bdc55d
8221430: StringBuffer(CharSequence) constructor truncates when -XX:-CompactStrings specified Reviewed-by: igerasim, rriggs Contributed-by: Andrew Leonard <andrew_m_leonard@uk.ibm.com>, Ivan Gerasimov <ivan.gerasimov@oracle.com>
src/java.base/share/classes/java/lang/AbstractStringBuilder.java
src/java.base/share/classes/java/lang/StringBuffer.java
src/java.base/share/classes/java/lang/StringBuilder.java
test/jdk/java/lang/StringBuffer/CompactStringBuffer.java
test/micro/org/openjdk/bench/java/lang/StringBuilders.java
--- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Tue Apr 09 18:26:36 2019 -0400
+++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Tue Apr 09 16:32:22 2019 -0700
@@ -92,19 +92,57 @@
     }
 
     /**
-     * Creates an AbstractStringBuilder with the specified coder and with
-     * the initial capacity equal to the smaller of (length + addition)
-     * and Integer.MAX_VALUE.
+     * Constructs an AbstractStringBuilder that contains the same characters
+     * as the specified {@code String}. The initial capacity of
+     * the string builder is {@code 16} plus the length of the
+     * {@code String} argument.
+     *
+     * @param      str   the string to copy.
      */
-    AbstractStringBuilder(byte coder, int length, int addition) {
+    AbstractStringBuilder(String str) {
+        int length = str.length();
+        int capacity = (length < Integer.MAX_VALUE - 16)
+                ? length + 16 : Integer.MAX_VALUE;
+        final byte initCoder = str.coder();
+        coder = initCoder;
+        value = (initCoder == LATIN1)
+                ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
+        append(str);
+    }
+
+    /**
+     * Constructs an AbstractStringBuilder that contains the same characters
+     * as the specified {@code CharSequence}. The initial capacity of
+     * the string builder is {@code 16} plus the length of the
+     * {@code CharSequence} argument.
+     *
+     * @param      seq   the sequence to copy.
+     */
+    AbstractStringBuilder(CharSequence seq) {
+        int length = seq.length();
         if (length < 0) {
             throw new NegativeArraySizeException("Negative length: " + length);
         }
-        this.coder = coder;
-        int capacity = (length < Integer.MAX_VALUE - addition)
-                ? length + addition : Integer.MAX_VALUE;
-        value = (coder == LATIN1)
+        int capacity = (length < Integer.MAX_VALUE - 16)
+                ? length + 16 : Integer.MAX_VALUE;
+
+        final byte initCoder;
+        if (COMPACT_STRINGS) {
+            if (seq instanceof AbstractStringBuilder) {
+                initCoder = ((AbstractStringBuilder)seq).getCoder();
+            } else if (seq instanceof String) {
+                initCoder = ((String)seq).coder();
+            } else {
+                initCoder = LATIN1;
+            }
+        } else {
+            initCoder = UTF16;
+        }
+
+        coder = initCoder;
+        value = (initCoder == LATIN1)
                 ? new byte[capacity] : StringUTF16.newBytesFor(capacity);
+        append(seq);
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/StringBuffer.java	Tue Apr 09 18:26:36 2019 -0400
+++ b/src/java.base/share/classes/java/lang/StringBuffer.java	Tue Apr 09 16:32:22 2019 -0700
@@ -148,8 +148,7 @@
      */
     @HotSpotIntrinsicCandidate
     public StringBuffer(String str) {
-        super(str.coder(), str.length(), 16);
-        append(str);
+        super(str);
     }
 
     /**
@@ -162,8 +161,7 @@
      * @since 1.5
      */
     public StringBuffer(CharSequence seq) {
-        super(String.LATIN1, seq.length(), 16);
-        append(seq);
+        super(seq);
     }
 
     /**
--- a/src/java.base/share/classes/java/lang/StringBuilder.java	Tue Apr 09 18:26:36 2019 -0400
+++ b/src/java.base/share/classes/java/lang/StringBuilder.java	Tue Apr 09 16:32:22 2019 -0700
@@ -121,8 +121,7 @@
      */
     @HotSpotIntrinsicCandidate
     public StringBuilder(String str) {
-        super(str.coder(), str.length(), 16);
-        append(str);
+        super(str);
     }
 
     /**
@@ -134,8 +133,7 @@
      * @param      seq   the sequence to copy.
      */
     public StringBuilder(CharSequence seq) {
-        super(String.LATIN1, seq.length(), 16);
-        append(seq);
+        super(seq);
     }
 
     /**
--- a/test/jdk/java/lang/StringBuffer/CompactStringBuffer.java	Tue Apr 09 18:26:36 2019 -0400
+++ b/test/jdk/java/lang/StringBuffer/CompactStringBuffer.java	Tue Apr 09 16:32:22 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2019, 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
@@ -30,7 +30,7 @@
 
 /*
  * @test
- * @bug 8077559
+ * @bug 8077559 8221430
  * @summary Tests Compact String. This test is testing StringBuffer
  *          behavior related to Compact String.
  * @run testng/othervm -XX:+CompactStrings CompactStringBuffer
@@ -440,6 +440,12 @@
               "abcdefgh1.23456");
         check(new StringBuffer().append(bmp).append(1.23456).toString(),
               "\u4e00\u4e01\u4e02\u4e03\u4e04\u4e05\u4e06\u4e07\u4e081.23456");
+
+        ////////////////////////////////////////////////////////////////////
+        check(new StringBuffer((CharSequence)new StringBuffer(ascii)).toString(),
+              ascii);
+        check(new StringBuffer((CharSequence)new StringBuffer(asciiMixed)).toString(),
+              asciiMixed);
     }
 
     private void checkGetChars(StringBuffer sb, int srcBegin, int srcEnd,
--- a/test/micro/org/openjdk/bench/java/lang/StringBuilders.java	Tue Apr 09 18:26:36 2019 -0400
+++ b/test/micro/org/openjdk/bench/java/lang/StringBuilders.java	Tue Apr 09 16:32:22 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2019, 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
@@ -42,6 +42,8 @@
     private String[] str16p8p7;
     private String[] str3p9p8;
     private String[] str22p40p31;
+    private StringBuilder sbLatin1;
+    private StringBuilder sbUtf16;
 
     @Setup
     public void setup() {
@@ -53,6 +55,8 @@
         str16p8p7 = new String[]{"1234567890123456", "12345678", "1234567"};
         str3p9p8 = new String[]{"123", "123456789", "12345678"};
         str22p40p31 = new String[]{"1234567890123456789012", "1234567890123456789012345678901234567890", "1234567890123456789012345678901"};
+        sbLatin1 = new StringBuilder("Latin1 string");
+        sbUtf16 = new StringBuilder("UTF-\uFF11\uFF16 string");
     }
 
     /** StringBuilder wins over StringMaker. */
@@ -256,4 +260,24 @@
         result.append("stringelinglinglinglong");
         return result.toString();
     }
+
+    @Benchmark
+    public StringBuilder fromLatin1String() {
+        return new StringBuilder("Latin1 string");
+    }
+
+    @Benchmark
+    public StringBuilder fromUtf16String() {
+        return new StringBuilder("UTF-\uFF11\uFF16 string");
+    }
+
+    @Benchmark
+    public StringBuilder fromLatin1StringBuilder() {
+        return new StringBuilder(sbLatin1);
+    }
+
+    @Benchmark
+    public StringBuilder fromUtf16StringBuilder() {
+        return new StringBuilder(sbUtf16);
+    }
 }