1 /* 2 * Copyright (c) 2015, 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 import java.lang.annotation.*; 25 import java.lang.reflect.*; 26 import java.util.Arrays; 27 28 /* 29 * @test 30 * @bug 8054307 31 * @summary Tests correctness of string related intrinsics and C2 optimizations. 32 * @run main/timeout=240 TestStringIntrinsics 33 */ 34 public class TestStringIntrinsics { 35 36 public enum Operation { 37 ARR_EQUALS_B, ARR_EQUALS_C, EQUALS, COMPARE_TO, INDEX_OF, INDEX_OF_CON_U, INDEX_OF_CON_L, 38 INDEX_OF_CON_UL, CONCAT, CONCAT_C, CONCAT_I, CONCAT_M, INDEX_OF_CHAR 39 } 40 41 @Retention(RetentionPolicy.RUNTIME) 42 @Target(ElementType.METHOD) 43 @interface Test { 44 Operation op(); 45 String constString() default ""; 46 String[] inStrings() default {}; 47 char[] inChars() default {}; 48 int[] inInts() default {}; 49 String[] outStrings() default {}; 50 } 51 52 public static void main(String[] args) throws Exception { 53 new TestStringIntrinsics().run(); 54 } 55 56 public void run() throws Exception { 57 // Build latin1 and UTF16 strings 58 StringBuilder latin1Builder = new StringBuilder(); 59 for (int i = 0; i <= 255; ++i) { 60 latin1Builder.append((char) i); 61 } 62 String latin1 = latin1Builder.toString(); 63 StringBuilder utf16Builder = new StringBuilder(); 64 for (int i = 0; i <= 10000; ++i) { 65 utf16Builder.append((char) i); 66 } 67 String utf16 = utf16Builder.toString(); 68 69 // Invoke test methods 70 for (Method m : TestStringIntrinsics.class.getMethods()) { 71 if (m.isAnnotationPresent(Test.class)) { 72 System.out.print("Checking " + m.getName() + "... "); 73 Operation op = m.getAnnotation(Test.class).op(); 74 Test antn = m.getAnnotation(Test.class); 75 if (isStringConcatTest(op)) { 76 checkStringConcat(op, m, antn); 77 } else { 78 checkIntrinsics(op, m, latin1, utf16, antn); 79 } 80 System.out.println("Done."); 81 } 82 } 83 } 84 85 private boolean isStringConcatTest(Operation op) { 86 return op == Operation.CONCAT || 87 op == Operation.CONCAT_C || 88 op == Operation.CONCAT_I || 89 op == Operation.CONCAT_M; 90 } 91 92 /** 93 * Checks correctness of the String.equals, String.compareTo and String.indexOf intrinsics. 94 * -XX:SpecialStringEquals 95 * -XX:SpecialStringCompareTo 96 * -XX:SpecialStringIndexOf 97 */ 98 private void checkIntrinsics(Operation op, Method m, String latin1, String utf16, Test antn) throws Exception { 99 for (int i = 0; i < 50_000; ++i) { 100 // Copy and permute latin1 and UTF16 string 101 char[] arrL = latin1.toCharArray(); 102 int indexL = i % arrL.length; 103 int mod = (arrL.length - arrL[indexL]); 104 int incL = i % ((mod != 0) ? mod : 1); 105 arrL[indexL] = (char) ((int) arrL[indexL] + incL); 106 String latin1Copy = String.valueOf(arrL); 107 108 char[] arrU = utf16.toCharArray(); 109 int indexU = i % arrU.length; 110 mod = (arrU.length - arrU[indexU]); 111 int incU = i % ((mod != 0) ? mod : 1); 112 arrU[indexU] = (char) ((int) arrU[indexU] + incU); 113 String utf16Copy = String.valueOf(arrU); 114 115 switch (op) { 116 case ARR_EQUALS_B: 117 invokeAndCheck(m, (incL == 0), latin1.getBytes("ISO-8859-1"), latin1Copy.getBytes("ISO-8859-1")); 118 invokeAndCheck(m, true, new byte[] {1, 2, 3}, new byte[] {1, 2, 3}); 119 invokeAndCheck(m, true, new byte[] {1}, new byte[] {1}); 120 invokeAndCheck(m, true, new byte[] {}, new byte[] {}); 121 break; 122 case ARR_EQUALS_C: 123 invokeAndCheck(m, (incU == 0), utf16.toCharArray(), arrU); 124 break; 125 case EQUALS: 126 invokeAndCheck(m, (incL == 0), latin1, latin1Copy); 127 invokeAndCheck(m, false, latin1, ""); 128 invokeAndCheck(m, false, "", latin1); 129 130 invokeAndCheck(m, (incU == 0), utf16, utf16Copy); 131 invokeAndCheck(m, false, utf16, ""); 132 invokeAndCheck(m, false, "", utf16); 133 134 invokeAndCheck(m, false, latin1, utf16); 135 break; 136 case COMPARE_TO: 137 invokeAndCheck(m, -incL, latin1, latin1Copy); 138 invokeAndCheck(m, latin1.length(), latin1, ""); 139 140 invokeAndCheck(m, -incU, utf16, utf16Copy); 141 invokeAndCheck(m, utf16.length(), utf16, ""); 142 143 // Cross coder 144 char cL = latin1.charAt(indexL); 145 char cU = utf16.charAt(indexU); 146 invokeAndCheck(m, cL - cU, latin1, latin1.replace(cL, cU)); 147 invokeAndCheck(m, cU - cL, utf16, utf16.replace(cU, cL)); 148 149 // Different lengths 150 invokeAndCheck(m, 1, "ABCD", "ABC"); 151 invokeAndCheck(m, -1, "\uff21\uff22\uff23", "\uff21\uff22\uff23\uff24"); 152 invokeAndCheck(m, 1, "ABC\uff24", "ABC"); 153 invokeAndCheck(m, 3, "ABC\uff24\uff25\uff26", "ABC"); 154 invokeAndCheck(m, -1, "ABC","ABC\uff24"); 155 invokeAndCheck(m, -3, "ABC","ABC\uff24\uff25\uff26"); 156 break; 157 case INDEX_OF: 158 invokeAndCheck(m, indexL, latin1, latin1.substring(indexL), (indexL > 42) ? 42 : 0); 159 invokeAndCheck(m, 0, latin1, "", 0); 160 161 invokeAndCheck(m, indexU, utf16, utf16.substring(indexU), (indexU > 42) ? 42 : 0); 162 invokeAndCheck(m, 0, utf16, "", 0); 163 164 // Cross coder 165 invokeAndCheck(m, -1, latin1.substring(0, indexL), utf16.substring(indexU), (indexL > 42) ? 42 : 0); 166 // Skip latin1 chars in utf16 string 167 int start = 256; 168 int end = indexU > start ? indexU : start; 169 invokeAndCheck(m, end-start, utf16.substring(start, end) + latin1.substring(indexL), latin1.substring(indexL), 0); 170 break; 171 case INDEX_OF_CON_L: 172 invokeAndCheck(m, antn.constString(), latin1); 173 break; 174 case INDEX_OF_CON_U: 175 invokeAndCheck(m, antn.constString(), utf16); 176 break; 177 case INDEX_OF_CON_UL: 178 invokeAndCheck(m, antn.constString(), utf16); 179 break; 180 case INDEX_OF_CHAR: 181 invokeAndCheck(m, 7, "abcdefg\uD800\uDC00", 65536, 0); 182 invokeAndCheck(m, -1, "abcdefg\uD800\uDC01", 65536, 0); 183 invokeAndCheck(m, -1, "abcdefg\uD800", 65536, 0); 184 invokeAndCheck(m, 3, "abc\u0107", 263, 0); 185 invokeAndCheck(m, -1, "abc\u0108", 263, 0); 186 invokeAndCheck(m, 7, "abcdefg\u0107", 263, 0); 187 invokeAndCheck(m, 7, "abcdefg\u0107", 263, -1); 188 invokeAndCheck(m, 0, "\u0107", 263, 0); 189 break; 190 default: 191 throw new RuntimeException("Unexpected operation."); 192 } 193 } 194 } 195 196 /** 197 * Checks correctness of the C2 string concatenation optimization. 198 * -XX:OptimizeStringConcat 199 */ 200 private void checkStringConcat(Operation op, Method m, Test antn) throws Exception { 201 for (int i = 0; i < 50_000; ++i) { 202 String[] result = antn.outStrings(); 203 switch(op) { 204 case CONCAT: 205 String[] strs = antn.inStrings(); 206 for (int j = 0; j < strs.length; ++j) { 207 invokeAndCheck(m, result[j], strs[j]); 208 } 209 break; 210 case CONCAT_C: 211 char[] ch = antn.inChars(); 212 for (int j = 0; j < ch.length; ++j) { 213 invokeAndCheck(m, result[j], ch[j]); 214 } 215 break; 216 case CONCAT_I: 217 int[] k = antn.inInts(); 218 for (int j = 0; j < k.length; ++j) { 219 invokeAndCheck(m, result[j], k[j]); 220 } 221 break; 222 case CONCAT_M: 223 strs = antn.inStrings(); 224 ch = antn.inChars(); 225 k = antn.inInts(); 226 for (int j = 0; j < strs.length; ++j) { 227 invokeAndCheck(m, result[j], strs[j], ch[j], k[j]); 228 } 229 break; 230 default: 231 throw new RuntimeException("Unexpected operation."); 232 } 233 } 234 } 235 236 /** 237 * Invokes method 'm' by passing arguments 'args' and checks if the 238 * returned value equals 'expectedResult'. 239 */ 240 private void invokeAndCheck(Method m, Object expectedResult, Object... args) throws Exception { 241 Object result = m.invoke(null, args); 242 if (!result.equals(expectedResult)) { 243 // System.out.println("Expected:"); 244 // System.out.println(expectedResult); 245 // System.out.println("Returned:"); 246 // System.out.println(result); 247 throw new RuntimeException("Result of '" + m.getName() + "' not equal to expected value."); 248 } 249 } 250 251 /* 252 * Constants 253 */ 254 static final char charU = '\uff21'; 255 static final char charL = 'A'; 256 static final String emptyString = ""; 257 static final String stringL = "abcdefghijklmnop"; 258 static final String stringSmallL = "abc"; 259 static final String stringU = "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28"; 260 static final String stringSmallU = "\u0f21\u0f22\u0f23"; 261 static final int constInt = 123; 262 static final int constIntNeg = -123; 263 264 /* 265 * Arrays.equals 266 */ 267 @Test(op = Operation.ARR_EQUALS_B) 268 public static boolean arrayEqualsB(byte[] a, byte[] b) { 269 return Arrays.equals(a, b); 270 } 271 272 @Test(op = Operation.ARR_EQUALS_C) 273 public static boolean arrayEqualsC(char[] a, char[] b) { 274 return Arrays.equals(a, b); 275 } 276 277 /* 278 * String.equals 279 */ 280 @Test(op = Operation.EQUALS) 281 public static boolean equals(String a, String b) { 282 return a.equals(b); 283 } 284 285 /* 286 * String.compareTo 287 */ 288 @Test(op = Operation.COMPARE_TO) 289 public static int compareTo(String a, String b) { 290 return a.compareTo(b); 291 } 292 293 /* 294 * String.indexOf 295 */ 296 @Test(op = Operation.INDEX_OF) 297 public static int indexOf(String a, String b, int from) { 298 return a.indexOf(b, from); 299 } 300 301 @Test(op = Operation.INDEX_OF_CON_U, constString = stringSmallU) 302 public static String indexOfConstU(String a) { 303 int result = a.indexOf(stringSmallU); 304 return a.substring(result, result + stringSmallU.length()); 305 } 306 307 @Test(op = Operation.INDEX_OF_CON_U, constString = stringU) 308 public static String indexOfConstLargeU(String a) { 309 int result = a.indexOf(stringU); 310 return a.substring(result, result + stringU.length()); 311 } 312 313 @Test(op = Operation.INDEX_OF_CON_U, constString = emptyString) 314 public static String indexOfConstEmptyU(String a) { 315 int result = a.indexOf(emptyString); 316 return a.substring(result, result + emptyString.length()); 317 } 318 319 @Test(op = Operation.INDEX_OF_CON_L, constString = stringSmallL) 320 public static String indexOfConstL(String a) { 321 int result = a.indexOf(stringSmallL); 322 return a.substring(result, result + stringSmallL.length()); 323 } 324 325 @Test(op = Operation.INDEX_OF_CON_L, constString = stringL) 326 public static String indexOfConstLargeL(String a) { 327 int result = a.indexOf(stringL); 328 return a.substring(result, result + stringL.length()); 329 } 330 331 @Test(op = Operation.INDEX_OF_CON_L, constString = emptyString) 332 public static String indexOfConstEmptyL(String a) { 333 int result = a.indexOf(emptyString); 334 return a.substring(result, result + emptyString.length()); 335 } 336 337 @Test(op = Operation.INDEX_OF_CON_UL, constString = stringSmallL) 338 public static String indexOfConstUL(String a) { 339 int result = a.indexOf(stringSmallL); 340 return a.substring(result, result + stringSmallL.length()); 341 } 342 343 @Test(op = Operation.INDEX_OF_CON_UL, constString = stringL) 344 public static String indexOfConstLargeUL(String a) { 345 int result = a.indexOf(stringL); 346 return a.substring(result, result + stringL.length()); 347 } 348 349 @Test(op = Operation.INDEX_OF_CHAR) 350 public static int indexOfChar(String a, int ch, int from) { 351 return a.indexOf(ch, from); 352 } 353 354 /* 355 * String concatenation optimization 356 */ 357 @Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"ABC", "\uff21\uff22\uff23"}) 358 public static String concatString(String a) { 359 return new StringBuilder().append(a).toString(); 360 } 361 362 @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {""}) 363 public static String concatStringEmpty(String a) { 364 return new StringBuilder().toString(); 365 } 366 367 @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"null"}) 368 public static String concatStringNull(String a) { 369 return new StringBuilder().append((String)null).toString(); 370 } 371 372 @Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"abcdefghijklmnopABCabc", "abcdefghijklmnop\uff21\uff22\uff23abc"}) 373 public static String concatStringConstL(String a) { 374 return new StringBuilder().append(stringL).append(a).append(stringSmallL).toString(); 375 } 376 377 @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"}) 378 public static String concatStringConstU(String a) { 379 return new StringBuilder().append(stringSmallU).append(a).append(stringU).toString(); 380 } 381 382 @Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"A", "\uff21"}) 383 public static String concatChar(char a) { 384 return new StringBuilder().append(a).toString(); 385 } 386 387 @Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"abcdefghijklmnopAabcA\uff21", "abcdefghijklmnop\uff21abcA\uff21"}) 388 public static String concatCharConstL(char a) { 389 return new StringBuilder().append(stringL).append(a).append(stringSmallL).append(charL).append(charU).toString(); 390 } 391 392 @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"}) 393 public static String concatCharConstU(char a) { 394 return new StringBuilder().append(stringSmallU).append(a).append(stringU).append(charU).append(charL).toString(); 395 } 396 397 @Test(op = Operation.CONCAT_I, inInts = {Integer.MIN_VALUE, -42, 42, Integer.MAX_VALUE}, outStrings = {"-2147483648", "-42", "42", "2147483647"}) 398 public static String concatInt(int a) { 399 return new StringBuilder().append(a).toString(); 400 } 401 402 @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"}) 403 public static String concatIntConstL(int b) { 404 return new StringBuilder().append(stringL).append(b).append(stringSmallL).append(constInt).append(constIntNeg).toString(); 405 } 406 407 @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"}) 408 public static String concatIntConstU(int b) { 409 return new StringBuilder().append(stringSmallU).append(b).append(stringU).append(constInt).append(constIntNeg).toString(); 410 } 411 412 @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"nullabcabcdefghijklmnopA123-123"}) 413 public static String concatConstL(String a) { 414 return new StringBuilder().append((String)null).append(stringSmallL).append(stringL).append(charL).append(constInt).append(constIntNeg).toString(); 415 } 416 417 @Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"nullabcabcdefghijklmnop\u0f21\u0f22\u0f23\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28A\uff21123-123"}) 418 public static String concatConstU(String a) { 419 return new StringBuilder().append((String)null).append(stringSmallL).append(stringL).append(stringSmallU).append(stringU).append(charL).append(charU).append(constInt).append(constIntNeg).toString(); 420 } 421 422 @Test(op = Operation.CONCAT_M, 423 inStrings = {"ABCDEFG", "ABCDEFG", "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28", "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28"}, 424 inChars = {'A', '\uff21', 'A', '\uff21'}, 425 inInts = {Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE}, 426 outStrings = {"ABCDEFGA-2147483648nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21ABCDEFGA-2147483648null", 427 "ABCDEFG\uff212147483647nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21ABCDEFG\uff212147483647null", 428 "\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", 429 "\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"}) 430 public static String concatMixed(String a, char b, int c) { 431 return new StringBuilder().append(a).append(b).append(c).append((String)null) 432 .append(stringL).append(constInt).append(constIntNeg).append(charL).append(stringU).append(charU) 433 .append(a).append(b).append(c).append((String)null).toString(); 434 } 435 }