changeset 60225:f67951f722a4

8240094: Optimize empty substring handling Reviewed-by: redestad, igerasim, jlaskey Contributed-by: sergei.tsypanov@yandex.ru
author redestad
date Wed, 26 Feb 2020 21:24:02 +0100
parents 2ec0ff304263
children 541b03673cdb
files src/java.base/share/classes/java/lang/String.java src/java.base/share/classes/java/lang/StringLatin1.java src/java.base/share/classes/java/lang/StringUTF16.java test/micro/org/openjdk/bench/java/lang/StringSubstring.java
diffstat 4 files changed, 23 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.base/share/classes/java/lang/String.java	Wed Feb 26 14:36:01 2020 -0500
+++ b/src/java.base/share/classes/java/lang/String.java	Wed Feb 26 21:24:02 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2020, 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
@@ -1819,7 +1819,7 @@
      * @param   src         the characters being searched.
      * @param   srcCoder    coder handles the mapping between bytes/chars
      * @param   srcCount    count of the source string.
-     * @param   tgt         the characters being searched for.
+     * @param   tgtStr      the characters being searched for.
      * @param   fromIndex   the index to begin searching from.
      */
     static int lastIndexOf(byte[] src, byte srcCoder, int srcCount,
@@ -1900,10 +1900,10 @@
     public String substring(int beginIndex, int endIndex) {
         int length = length();
         checkBoundsBeginEnd(beginIndex, endIndex, length);
-        int subLen = endIndex - beginIndex;
         if (beginIndex == 0 && endIndex == length) {
             return this;
         }
+        int subLen = endIndex - beginIndex;
         return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
                           : StringUTF16.newString(value, beginIndex, subLen);
     }
--- a/src/java.base/share/classes/java/lang/StringLatin1.java	Wed Feb 26 14:36:01 2020 -0500
+++ b/src/java.base/share/classes/java/lang/StringLatin1.java	Wed Feb 26 21:24:02 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, 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
@@ -630,17 +630,11 @@
 
     public static String stripLeading(byte[] value) {
         int left = indexOfNonWhitespace(value);
-        if (left == value.length) {
-            return "";
-        }
         return (left != 0) ? newString(value, left, value.length - left) : null;
     }
 
     public static String stripTrailing(byte[] value) {
         int right = lastIndexOfNonWhitespace(value);
-        if (right == 0) {
-            return "";
-        }
         return (right != value.length) ? newString(value, 0, right) : null;
     }
 
@@ -764,6 +758,9 @@
     }
 
     public static String newString(byte[] val, int index, int len) {
+        if (len == 0) {
+            return "";
+        }
         return new String(Arrays.copyOfRange(val, index, index + len),
                           LATIN1);
     }
--- a/src/java.base/share/classes/java/lang/StringUTF16.java	Wed Feb 26 14:36:01 2020 -0500
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java	Wed Feb 26 21:24:02 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, 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
@@ -1016,18 +1016,12 @@
     public static String stripLeading(byte[] value) {
         int length = value.length >>> 1;
         int left = indexOfNonWhitespace(value);
-        if (left == length) {
-            return "";
-        }
         return (left != 0) ? newString(value, left, length - left) : null;
     }
 
     public static String stripTrailing(byte[] value) {
         int length = value.length >>> 1;
         int right = lastIndexOfNonWhitespace(value);
-        if (right == 0) {
-            return "";
-        }
         return (right != length) ? newString(value, 0, right) : null;
     }
 
@@ -1132,6 +1126,9 @@
     }
 
     public static String newString(byte[] val, int index, int len) {
+        if (len == 0) {
+            return "";
+        }
         if (String.COMPACT_STRINGS) {
             byte[] buf = compress(val, index, len);
             if (buf != null) {
--- a/test/micro/org/openjdk/bench/java/lang/StringSubstring.java	Wed Feb 26 14:36:01 2020 -0500
+++ b/test/micro/org/openjdk/bench/java/lang/StringSubstring.java	Wed Feb 26 21:24:02 2020 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2020, 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
@@ -28,6 +28,9 @@
 
 @BenchmarkMode(Mode.AverageTime)
 @OutputTimeUnit(TimeUnit.NANOSECONDS)
+@Fork(value = 3)
+@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
+@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
 @State(Scope.Benchmark)
 public class StringSubstring {
 
@@ -42,4 +45,12 @@
     public String from26toEnd1() {
         return s.substring(26, s.length());
     }
+
+    /**
+     * An empty substring should not allocate a new String
+     */
+    @Benchmark
+    public String empty() {
+        return s.substring(17, 17);
+    }
 }