1 /*
2  * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 8054307
27  * @summary Tests correctness of string related intrinsics and C2 optimizations.
28  * @library /test/lib
29  *
30  * @run main/timeout=240 compiler.intrinsics.string.TestStringIntrinsics
31  */
32 
33 package compiler.intrinsics.string;
34 
35 import jdk.test.lib.format.Format;
36 import jdk.test.lib.format.ArrayCodec;
37 
38 import java.lang.annotation.ElementType;
39 import java.lang.annotation.Retention;
40 import java.lang.annotation.RetentionPolicy;
41 import java.lang.annotation.Target;
42 import java.lang.reflect.Method;
43 import java.util.Arrays;
44 
45 public class TestStringIntrinsics {
46 
47     public enum Operation {
48         ARR_EQUALS_B, ARR_EQUALS_C, EQUALS, COMPARE_TO, INDEX_OF, INDEX_OF_CON_U, INDEX_OF_CON_L,
49         INDEX_OF_CON_UL, CONCAT, CONCAT_C, CONCAT_I, CONCAT_M, INDEX_OF_CHAR
50     }
51 
52     @Retention(RetentionPolicy.RUNTIME)
53     @Target(ElementType.METHOD)
54     @interface Test {
op()55         Operation op();
constString()56         String constString() default "";
inStrings()57         String[] inStrings() default {};
inChars()58         char[] inChars() default {};
inInts()59         int[] inInts() default {};
outStrings()60         String[] outStrings() default {};
61     }
62 
main(String[] args)63     public static void main(String[] args) throws Exception {
64         new TestStringIntrinsics().run();
65     }
66 
run()67     public void run() throws Exception {
68         // Build latin1 and UTF16 strings
69         StringBuilder latin1Builder = new StringBuilder();
70         for (int i = 0; i <= 255; ++i) {
71             latin1Builder.append((char) i);
72         }
73         String latin1 = latin1Builder.toString();
74         StringBuilder utf16Builder = new StringBuilder();
75         for (int i = 0; i <= 10000; ++i) {
76             utf16Builder.append((char) i);
77         }
78         String utf16 = utf16Builder.toString();
79 
80         // Invoke test methods
81         for (Method m : TestStringIntrinsics.class.getMethods()) {
82             if (m.isAnnotationPresent(Test.class)) {
83                 System.out.print("Checking " + m.getName() + "... ");
84                 Test antn = m.getAnnotation(Test.class);
85                 Operation op = antn.op();
86                 if (isStringConcatTest(op)) {
87                     checkStringConcat(op, m, antn);
88                 } else {
89                     checkIntrinsics(op, m, latin1, utf16, antn);
90                 }
91                 System.out.println("Done.");
92             }
93         }
94     }
95 
isStringConcatTest(Operation op)96     private boolean isStringConcatTest(Operation op) {
97         return op == Operation.CONCAT ||
98                op == Operation.CONCAT_C ||
99                op == Operation.CONCAT_I ||
100                op == Operation.CONCAT_M;
101     }
102 
103     /**
104      * Checks correctness of the String.equals, String.compareTo and String.indexOf intrinsics.
105      * -XX:SpecialStringEquals
106      * -XX:SpecialStringCompareTo
107      * -XX:SpecialStringIndexOf
108      */
checkIntrinsics(Operation op, Method m, String latin1, String utf16, Test antn)109     private void checkIntrinsics(Operation op, Method m, String latin1, String utf16, Test antn) throws Exception {
110         for (int i = 0; i < 50_000; ++i) {
111             // Copy and permute latin1 and UTF16 string
112             char[] arrL = latin1.toCharArray();
113             int indexL = i % arrL.length;
114             int mod = (arrL.length - arrL[indexL]);
115             int incL = i % ((mod != 0) ? mod : 1);
116             arrL[indexL] = (char) ((int) arrL[indexL] + incL);
117             String latin1Copy = String.valueOf(arrL);
118 
119             char[] arrU = utf16.toCharArray();
120             int indexU = i % arrU.length;
121             mod = (arrU.length - arrU[indexU]);
122             int incU = i % ((mod != 0) ? mod : 1);
123             arrU[indexU] = (char) ((int) arrU[indexU] + incU);
124             String utf16Copy = String.valueOf(arrU);
125 
126             switch (op) {
127             case ARR_EQUALS_B:
128                 invokeAndCompareArrays(m, (incL == 0), latin1.getBytes("ISO-8859-1"), latin1Copy.getBytes("ISO-8859-1"));
129                 invokeAndCompareArrays(m, true, new byte[] {1, 2, 3}, new byte[] {1, 2, 3});
130                 invokeAndCompareArrays(m, true, new byte[] {1}, new byte[] {1});
131                 invokeAndCompareArrays(m, true, new byte[] {}, new byte[] {});
132                 break;
133             case ARR_EQUALS_C:
134                 invokeAndCompareArrays(m, (incU == 0), utf16.toCharArray(), arrU);
135                 break;
136             case EQUALS:
137                 invokeAndCheck(m, (incL == 0), latin1, latin1Copy);
138                 invokeAndCheck(m, false, latin1, "");
139                 invokeAndCheck(m, false, "", latin1);
140 
141                 invokeAndCheck(m, (incU == 0), utf16, utf16Copy);
142                 invokeAndCheck(m, false, utf16, "");
143                 invokeAndCheck(m, false, "", utf16);
144 
145                 invokeAndCheck(m, false, latin1, utf16);
146                 break;
147             case COMPARE_TO:
148                 invokeAndCheck(m, -incL, latin1, latin1Copy);
149                 invokeAndCheck(m, latin1.length(), latin1, "");
150 
151                 invokeAndCheck(m, -incU, utf16, utf16Copy);
152                 invokeAndCheck(m, utf16.length(), utf16, "");
153 
154                 // Cross coder
155                 char cL = latin1.charAt(indexL);
156                 char cU = utf16.charAt(indexU);
157                 invokeAndCheck(m, cL - cU, latin1, latin1.replace(cL, cU));
158                 invokeAndCheck(m, cU - cL, utf16, utf16.replace(cU, cL));
159 
160                 // Different lengths
161                 invokeAndCheck(m, 1, "ABCD", "ABC");
162                 invokeAndCheck(m, -1, "\uff21\uff22\uff23", "\uff21\uff22\uff23\uff24");
163                 invokeAndCheck(m, 1, "ABC\uff24", "ABC");
164                 invokeAndCheck(m, 3, "ABC\uff24\uff25\uff26", "ABC");
165                 invokeAndCheck(m, -1, "ABC","ABC\uff24");
166                 invokeAndCheck(m, -3, "ABC","ABC\uff24\uff25\uff26");
167                 break;
168             case INDEX_OF:
169                 invokeAndCheck(m, indexL, latin1, latin1.substring(indexL), (indexL > 42) ? 42 : 0);
170                 invokeAndCheck(m, 0, latin1, "", 0);
171 
172                 invokeAndCheck(m, indexU, utf16, utf16.substring(indexU), (indexU > 42) ? 42 : 0);
173                 invokeAndCheck(m, 0, utf16, "", 0);
174 
175                 // Cross coder
176                 invokeAndCheck(m, -1, latin1.substring(0, indexL), utf16.substring(indexU), (indexL > 42) ? 42 : 0);
177                 // Skip latin1 chars in utf16 string
178                 int start = 256;
179                 int end = indexU > start ? indexU : start;
180                 invokeAndCheck(m, end-start, utf16.substring(start, end) + latin1.substring(indexL), latin1.substring(indexL), 0);
181                 break;
182             case INDEX_OF_CON_L:
183                 invokeAndCheck(m, antn.constString(), latin1);
184                 break;
185             case INDEX_OF_CON_U:
186                 invokeAndCheck(m, antn.constString(), utf16);
187                 break;
188             case INDEX_OF_CON_UL:
189                 invokeAndCheck(m, antn.constString(), utf16);
190                 break;
191             case INDEX_OF_CHAR:
192                 invokeAndCheck(m, 7, "abcdefg\uD800\uDC00", 65536, 0);
193                 invokeAndCheck(m, -1, "abcdefg\uD800\uDC01", 65536, 0);
194                 invokeAndCheck(m, -1, "abcdefg\uD800", 65536, 0);
195                 invokeAndCheck(m, 3, "abc\u0107", 263, 0);
196                 invokeAndCheck(m, -1, "abc\u0108", 263, 0);
197                 invokeAndCheck(m, 7, "abcdefg\u0107", 263, 0);
198                 invokeAndCheck(m, 7, "abcdefg\u0107", 263, -1);
199                 invokeAndCheck(m, 0, "\u0107", 263, 0);
200                 break;
201             default:
202                 throw new RuntimeException("Unexpected operation.");
203             }
204         }
205     }
206 
207     /**
208      * Checks correctness of the C2 string concatenation optimization.
209      * -XX:OptimizeStringConcat
210      */
checkStringConcat(Operation op, Method m, Test antn)211     private void checkStringConcat(Operation op, Method m, Test antn) throws Exception {
212         for (int i = 0; i < 50_000; ++i) {
213             String[] result = antn.outStrings();
214             switch(op) {
215             case CONCAT:
216                 String[] strs = antn.inStrings();
217                 for (int j = 0; j < strs.length; ++j) {
218                     invokeAndCheck(m, result[j], strs[j]);
219                 }
220                 break;
221             case CONCAT_C:
222                 char[] ch = antn.inChars();
223                 for (int j = 0; j < ch.length; ++j) {
224                     invokeAndCheck(m, result[j], ch[j]);
225                 }
226                 break;
227             case CONCAT_I:
228                 int[] k = antn.inInts();
229                 for (int j = 0; j < k.length; ++j) {
230                     invokeAndCheck(m, result[j], k[j]);
231                 }
232                 break;
233             case CONCAT_M:
234                 strs = antn.inStrings();
235                 ch = antn.inChars();
236                 k = antn.inInts();
237                 for (int j = 0; j < strs.length; ++j) {
238                     invokeAndCheck(m, result[j], strs[j], ch[j], k[j]);
239                 }
240                 break;
241             default:
242                 throw new RuntimeException("Unexpected operation.");
243             }
244         }
245     }
246 
247     /**
248      * Invokes method 'm' by passing arguments the two 'args' (which are supposed to be arrays)
249      * checks if the returned value. In case of error and arrays being not equal, prints their difference.
250      */
invokeAndCompareArrays(Method m, boolean expectedResult, Object arg0, Object arg1)251     private void invokeAndCompareArrays(Method m, boolean expectedResult, Object arg0, Object arg1) throws Exception {
252         boolean result = (Boolean)m.invoke(null, arg0, arg1);
253         if (expectedResult == result)
254             return;
255 
256         String cause = String.format("Result: (%b) of '%s' is not equal to expected (%b)",
257                         result, m.getName(), expectedResult);
258 
259         if (expectedResult == true) {
260             System.err.println(cause);
261             System.err.println(Format.arrayDiff(arg0, arg1));
262         } else {
263             System.err.println(cause);
264             System.err.printf("First array argument: %n    %s%n", ArrayCodec.format(arg0));
265         }
266 
267         throw new RuntimeException(cause);
268     }
269 
270     /**
271      * Invokes method 'm' by passing arguments 'args' and checks if the
272      * returned value equals 'expectedResult'.
273      */
invokeAndCheck(Method m, Object expectedResult, Object... args)274     private void invokeAndCheck(Method m, Object expectedResult, Object... args) throws Exception {
275         Object actualResult = m.invoke(null, args);
276         if (!actualResult.equals(expectedResult)) {
277             var nl = System.lineSeparator();
278             StringBuilder msgBuilder = new StringBuilder();
279             msgBuilder.append("Actual result of '" + m.getName() + "' is not equal to expected value." + nl);
280             msgBuilder.append("Expected: " + Format.asLiteral(expectedResult) + nl);
281             msgBuilder.append("Actual: " + Format.asLiteral(actualResult));
282 
283             for (int i = 0; i < args.length; i++) {
284                 msgBuilder.append(nl + "    Arg" + i + ": " + Format.asLiteral(args[i]));
285             }
286 
287             final String message = msgBuilder.toString();
288             System.err.println(message);
289             throw new RuntimeException(message);
290         }
291     }
292 
293     /*
294      * Constants
295      */
296     static final char charU = '\uff21';
297     static final char charL = 'A';
298     static final String emptyString = "";
299     static final String stringL = "abcdefghijklmnop";
300     static final String stringSmallL = "abc";
301     static final String stringU = "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28";
302     static final String stringSmallU = "\u0f21\u0f22\u0f23";
303     static final int constInt = 123;
304     static final int constIntNeg = -123;
305 
306     /*
307      * Arrays.equals
308      */
309     @Test(op = Operation.ARR_EQUALS_B)
arrayEqualsB(byte[] a, byte[] b)310     public static boolean arrayEqualsB(byte[] a, byte[] b) {
311       return Arrays.equals(a, b);
312     }
313 
314     @Test(op = Operation.ARR_EQUALS_C)
arrayEqualsC(char[] a, char[] b)315     public static boolean arrayEqualsC(char[] a, char[] b) {
316       return Arrays.equals(a, b);
317     }
318 
319     /*
320      * String.equals
321      */
322     @Test(op = Operation.EQUALS)
equals(String a, String b)323     public static boolean equals(String a, String b) {
324         return a.equals(b);
325     }
326 
327     /*
328      * String.compareTo
329      */
330     @Test(op = Operation.COMPARE_TO)
compareTo(String a, String b)331     public static int compareTo(String a, String b) {
332         return a.compareTo(b);
333     }
334 
335     /*
336      * String.indexOf
337      */
338     @Test(op = Operation.INDEX_OF)
indexOf(String a, String b, int from)339     public static int indexOf(String a, String b, int from) {
340         return a.indexOf(b, from);
341     }
342 
343     @Test(op = Operation.INDEX_OF_CON_U, constString = stringSmallU)
indexOfConstU(String a)344     public static String indexOfConstU(String a) {
345         int result = a.indexOf(stringSmallU);
346         return a.substring(result, result + stringSmallU.length());
347     }
348 
349     @Test(op = Operation.INDEX_OF_CON_U, constString = stringU)
indexOfConstLargeU(String a)350     public static String indexOfConstLargeU(String a) {
351         int result = a.indexOf(stringU);
352         return a.substring(result, result + stringU.length());
353     }
354 
355     @Test(op = Operation.INDEX_OF_CON_U, constString = emptyString)
indexOfConstEmptyU(String a)356     public static String indexOfConstEmptyU(String a) {
357         int result = a.indexOf(emptyString);
358         return a.substring(result, result + emptyString.length());
359     }
360 
361     @Test(op = Operation.INDEX_OF_CON_L, constString = stringSmallL)
indexOfConstL(String a)362     public static String indexOfConstL(String a) {
363         int result = a.indexOf(stringSmallL);
364         return a.substring(result, result + stringSmallL.length());
365     }
366 
367     @Test(op = Operation.INDEX_OF_CON_L, constString = stringL)
indexOfConstLargeL(String a)368     public static String indexOfConstLargeL(String a) {
369         int result = a.indexOf(stringL);
370         return a.substring(result, result + stringL.length());
371     }
372 
373     @Test(op = Operation.INDEX_OF_CON_L, constString = emptyString)
indexOfConstEmptyL(String a)374     public static String indexOfConstEmptyL(String a) {
375         int result = a.indexOf(emptyString);
376         return a.substring(result, result + emptyString.length());
377     }
378 
379     @Test(op = Operation.INDEX_OF_CON_UL, constString = stringSmallL)
indexOfConstUL(String a)380     public static String indexOfConstUL(String a) {
381         int result = a.indexOf(stringSmallL);
382         return a.substring(result, result + stringSmallL.length());
383     }
384 
385     @Test(op = Operation.INDEX_OF_CON_UL, constString = stringL)
indexOfConstLargeUL(String a)386     public static String indexOfConstLargeUL(String a) {
387         int result = a.indexOf(stringL);
388         return a.substring(result, result + stringL.length());
389     }
390 
391     @Test(op = Operation.INDEX_OF_CHAR)
indexOfChar(String a, int ch, int from)392     public static int indexOfChar(String a, int ch, int from) {
393         return a.indexOf(ch, from);
394     }
395 
396     /*
397      * String concatenation optimization
398      */
399     @Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"ABC", "\uff21\uff22\uff23"})
concatString(String a)400     public static String concatString(String a) {
401         return new StringBuilder().append(a).toString();
402     }
403 
404     @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {""})
concatStringEmpty(String a)405     public static String concatStringEmpty(String a) {
406         return new StringBuilder().toString();
407     }
408 
409     @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"null"})
concatStringNull(String a)410     public static String concatStringNull(String a) {
411         return new StringBuilder().append((String)null).toString();
412     }
413 
414     @Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"abcdefghijklmnopABCabc", "abcdefghijklmnop\uff21\uff22\uff23abc"})
concatStringConstL(String a)415     public static String concatStringConstL(String a) {
416         return new StringBuilder().append(stringL).append(a).append(stringSmallL).toString();
417     }
418 
419     @Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"\u0f21\u0f22\u0f23ABC\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28", "\u0f21\u0f22\u0f23\uff21\uff22\uff23\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28"})
concatStringConstU(String a)420     public static String concatStringConstU(String a) {
421         return new StringBuilder().append(stringSmallU).append(a).append(stringU).toString();
422     }
423 
424     @Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"A", "\uff21"})
concatChar(char a)425     public static String concatChar(char a) {
426         return new StringBuilder().append(a).toString();
427     }
428 
429     @Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"abcdefghijklmnopAabcA\uff21", "abcdefghijklmnop\uff21abcA\uff21"})
concatCharConstL(char a)430     public static String concatCharConstL(char a) {
431         return new StringBuilder().append(stringL).append(a).append(stringSmallL).append(charL).append(charU).toString();
432     }
433 
434     @Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"\u0f21\u0f22\u0f23A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21A", "\u0f21\u0f22\u0f23\uff21\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21A"})
concatCharConstU(char a)435     public static String concatCharConstU(char a) {
436         return new StringBuilder().append(stringSmallU).append(a).append(stringU).append(charU).append(charL).toString();
437     }
438 
439     @Test(op = Operation.CONCAT_I, inInts = {Integer.MIN_VALUE, -42, 42, Integer.MAX_VALUE}, outStrings = {"-2147483648", "-42", "42", "2147483647"})
concatInt(int a)440     public static String concatInt(int a) {
441         return new StringBuilder().append(a).toString();
442     }
443 
444     @Test(op = Operation.CONCAT_I, inInts = {Integer.MIN_VALUE, -42, 42, Integer.MAX_VALUE}, outStrings = {"abcdefghijklmnop-2147483648abc123-123", "abcdefghijklmnop-42abc123-123", "abcdefghijklmnop42abc123-123", "abcdefghijklmnop2147483647abc123-123"})
concatIntConstL(int b)445     public static String concatIntConstL(int b) {
446         return new StringBuilder().append(stringL).append(b).append(stringSmallL).append(constInt).append(constIntNeg).toString();
447     }
448 
449     @Test(op = Operation.CONCAT_I, inInts = {Integer.MIN_VALUE, -42, 42, Integer.MAX_VALUE}, outStrings = {"\u0f21\u0f22\u0f23-2147483648\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123", "\u0f21\u0f22\u0f23-42\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123", "\u0f21\u0f22\u0f2342\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123", "\u0f21\u0f22\u0f232147483647\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123"})
concatIntConstU(int b)450     public static String concatIntConstU(int b) {
451         return new StringBuilder().append(stringSmallU).append(b).append(stringU).append(constInt).append(constIntNeg).toString();
452     }
453 
454     @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"nullabcabcdefghijklmnopA123-123"})
concatConstL(String a)455     public static String concatConstL(String a) {
456         return new StringBuilder().append((String)null).append(stringSmallL).append(stringL).append(charL).append(constInt).append(constIntNeg).toString();
457     }
458 
459     @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"nullabcabcdefghijklmnop\u0f21\u0f22\u0f23\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28A\uff21123-123"})
concatConstU(String a)460     public static String concatConstU(String a) {
461         return new StringBuilder().append((String)null).append(stringSmallL).append(stringL).append(stringSmallU).append(stringU).append(charL).append(charU).append(constInt).append(constIntNeg).toString();
462     }
463 
464     @Test(op = Operation.CONCAT_M,
465           inStrings = {"ABCDEFG", "ABCDEFG", "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28", "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28"},
466           inChars = {'A', '\uff21', 'A', '\uff21'},
467           inInts = {Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE},
468           outStrings = {"ABCDEFGA-2147483648nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21ABCDEFGA-2147483648null",
469                         "ABCDEFG\uff212147483647nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21ABCDEFG\uff212147483647null",
470                         "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28A-2147483648nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28A-2147483648null",
471             "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff212147483647nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff212147483647null"})
concatMixed(String a, char b, int c)472     public static String concatMixed(String a, char b, int c) {
473         return new StringBuilder().append(a).append(b).append(c).append((String)null)
474                 .append(stringL).append(constInt).append(constIntNeg).append(charL).append(stringU).append(charU)
475                 .append(a).append(b).append(c).append((String)null).toString();
476     }
477 }
478