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