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