TestArrayCopyAsLoadsStores.java revision 7935:54e0f8b411a8
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 6912521 27 * @summary small array copy as loads/stores 28 * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestArrayCopyAsLoadsStores::m* -XX:TypeProfileLevel=200 TestArrayCopyAsLoadsStores 29 * @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:CompileCommand=dontinline,TestArrayCopyAsLoadsStores::m* -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode -XX:TypeProfileLevel=200 TestArrayCopyAsLoadsStores 30 * 31 */ 32 33import java.lang.annotation.*; 34import java.lang.reflect.*; 35import java.util.*; 36 37public class TestArrayCopyAsLoadsStores { 38 39 public enum ArraySrc { 40 SMALL, 41 LARGE, 42 ZERO 43 } 44 45 public enum ArrayDst { 46 NONE, 47 NEW, 48 SRC 49 } 50 51 static class A { 52 } 53 54 static class B extends A { 55 } 56 57 static final A[] small_a_src = new A[5]; 58 static final A[] large_a_src = new A[10]; 59 static final A[] zero_a_src = new A[0]; 60 static final int[] small_int_src = new int[5]; 61 static final int[] large_int_src = new int[10]; 62 static final int[] zero_int_src = new int[0]; 63 static final Object[] small_object_src = new Object[5]; 64 static Object src; 65 66 @Retention(RetentionPolicy.RUNTIME) 67 @interface Args { 68 ArraySrc src(); 69 ArrayDst dst() default ArrayDst.NONE; 70 int[] extra_args() default {}; 71 } 72 73 // array clone should be compiled as loads/stores 74 @Args(src=ArraySrc.SMALL) 75 static A[] m1() throws CloneNotSupportedException { 76 return (A[])small_a_src.clone(); 77 } 78 79 @Args(src=ArraySrc.SMALL) 80 static int[] m2() throws CloneNotSupportedException { 81 return (int[])small_int_src.clone(); 82 } 83 84 // new array allocation should be optimized out 85 @Args(src=ArraySrc.SMALL) 86 static int m3() throws CloneNotSupportedException { 87 int[] array_clone = (int[])small_int_src.clone(); 88 return array_clone[0] + array_clone[1] + array_clone[2] + 89 array_clone[3] + array_clone[4]; 90 } 91 92 // should not be compiled as loads/stores 93 @Args(src=ArraySrc.LARGE) 94 static int[] m4() throws CloneNotSupportedException { 95 return (int[])large_int_src.clone(); 96 } 97 98 // check that array of length 0 is handled correctly 99 @Args(src=ArraySrc.ZERO) 100 static int[] m5() throws CloneNotSupportedException { 101 return (int[])zero_int_src.clone(); 102 } 103 104 // array copy should be compiled as loads/stores 105 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NEW) 106 static void m6(int[] src, int[] dest) { 107 System.arraycopy(src, 0, dest, 0, 5); 108 } 109 110 // array copy should not be compiled as loads/stores 111 @Args(src=ArraySrc.LARGE, dst=ArrayDst.NEW) 112 static void m7(int[] src, int[] dest) { 113 System.arraycopy(src, 0, dest, 0, 10); 114 } 115 116 // array copy should be compiled as loads/stores 117 @Args(src=ArraySrc.SMALL) 118 static A[] m8(A[] src) { 119 src[0] = src[0]; // force null check 120 A[] dest = new A[5]; 121 System.arraycopy(src, 0, dest, 0, 5); 122 return dest; 123 } 124 125 // array copy should not be compiled as loads/stores: we would 126 // need to emit GC barriers 127 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NEW) 128 static void m9(A[] src, A[] dest) { 129 System.arraycopy(src, 0, dest, 0, 5); 130 } 131 132 // overlapping array regions: copy backward 133 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC) 134 static void m10(int[] src, int[] dest) { 135 System.arraycopy(src, 0, dest, 1, 4); 136 } 137 138 static boolean m10_check(int[] src, int[] dest) { 139 boolean failure = false; 140 for (int i = 0; i < 5; i++) { 141 int j = Math.max(i - 1, 0); 142 if (dest[i] != src[j]) { 143 System.out.println("Test m10 failed for " + i + " src[" + j +"]=" + src[j] + ", dest[" + i + "]=" + dest[i]); 144 failure = true; 145 } 146 } 147 return failure; 148 } 149 150 // overlapping array regions: copy forward 151 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC) 152 static void m11(int[] src, int[] dest) { 153 System.arraycopy(src, 1, dest, 0, 4); 154 } 155 156 static boolean m11_check(int[] src, int[] dest) { 157 boolean failure = false; 158 for (int i = 0; i < 5; i++) { 159 int j = Math.min(i + 1, 4); 160 if (dest[i] != src[j]) { 161 System.out.println("Test m11 failed for " + i + " src[" + j +"]=" + src[j] + ", dest[" + i + "]=" + dest[i]); 162 failure = true; 163 } 164 } 165 return failure; 166 } 167 168 // overlapping array region with unknown src/dest offsets: compiled code must include both forward and backward copies 169 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC, extra_args={0,1}) 170 static void m12(int[] src, int[] dest, int srcPos, int destPos) { 171 System.arraycopy(src, srcPos, dest, destPos, 4); 172 } 173 174 static boolean m12_check(int[] src, int[] dest) { 175 boolean failure = false; 176 for (int i = 0; i < 5; i++) { 177 int j = Math.max(i - 1, 0); 178 if (dest[i] != src[j]) { 179 System.out.println("Test m10 failed for " + i + " src[" + j +"]=" + src[j] + ", dest[" + i + "]=" + dest[i]); 180 failure = true; 181 } 182 } 183 return failure; 184 } 185 186 // Array allocation and copy should optimize out 187 @Args(src=ArraySrc.SMALL) 188 static int m13(int[] src) { 189 int[] dest = new int[5]; 190 System.arraycopy(src, 0, dest, 0, 5); 191 return dest[0] + dest[1] + dest[2] + dest[3] + dest[4]; 192 } 193 194 // Check that copy of length 0 is handled correctly 195 @Args(src=ArraySrc.ZERO, dst=ArrayDst.NEW) 196 static void m14(int[] src, int[] dest) { 197 System.arraycopy(src, 0, dest, 0, 0); 198 } 199 200 // copyOf should compile to loads/stores 201 @Args(src=ArraySrc.SMALL) 202 static A[] m15() { 203 return Arrays.copyOf(small_a_src, 5, A[].class); 204 } 205 206 static Object[] helper16(int i) { 207 Object[] arr = null; 208 if ((i%2) == 0) { 209 arr = small_a_src; 210 } else { 211 arr = small_object_src; 212 } 213 return arr; 214 } 215 216 // CopyOf may need subtype check 217 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 218 static A[] m16(A[] unused_src, int i) { 219 Object[] arr = helper16(i); 220 return Arrays.copyOf(arr, 5, A[].class); 221 } 222 223 static Object[] helper17_1(int i) { 224 Object[] arr = null; 225 if ((i%2) == 0) { 226 arr = small_a_src; 227 } else { 228 arr = small_object_src; 229 } 230 return arr; 231 } 232 233 static A[] helper17_2(Object[] arr) { 234 return Arrays.copyOf(arr, 5, A[].class); 235 } 236 237 // CopyOf may leverage type speculation 238 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 239 static A[] m17(A[] unused_src, int i) { 240 Object[] arr = helper17_1(i); 241 return helper17_2(arr); 242 } 243 244 static Object[] helper18_1(int i) { 245 Object[] arr = null; 246 if ((i%2) == 0) { 247 arr = small_a_src; 248 } else { 249 arr = small_object_src; 250 } 251 return arr; 252 } 253 254 static Object[] helper18_2(Object[] arr) { 255 return Arrays.copyOf(arr, 5, Object[].class); 256 } 257 258 // CopyOf should not attempt to use type speculation if it's not needed 259 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 260 static Object[] m18(A[] unused_src, int i) { 261 Object[] arr = helper18_1(i); 262 return helper18_2(arr); 263 } 264 265 static Object[] helper19(int i) { 266 Object[] arr = null; 267 if ((i%2) == 0) { 268 arr = small_a_src; 269 } else { 270 arr = small_object_src; 271 } 272 return arr; 273 } 274 275 // CopyOf may need subtype check. Test is run to make type check 276 // fail and cause deoptimization. Next compilation should not 277 // compile as loads/stores because the first compilation 278 // deoptimized. 279 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 280 static A[] m19(A[] unused_src, int i) { 281 Object[] arr = helper19(i); 282 return Arrays.copyOf(arr, 5, A[].class); 283 } 284 285 // copyOf for large array should not compile to loads/stores 286 @Args(src=ArraySrc.LARGE) 287 static A[] m20() { 288 return Arrays.copyOf(large_a_src, 10, A[].class); 289 } 290 291 // check zero length copyOf is handled correctly 292 @Args(src=ArraySrc.ZERO) 293 static A[] m21() { 294 return Arrays.copyOf(zero_a_src, 0, A[].class); 295 } 296 297 // Run with srcPos=0 for a 1st compile, then with incorrect value 298 // of srcPos to cause deoptimization, then with srcPos=0 for a 2nd 299 // compile. The 2nd compile shouldn't turn arraycopy into 300 // loads/stores because input arguments are no longer known to be 301 // valid. 302 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NEW, extra_args={0}) 303 static void m22(int[] src, int[] dest, int srcPos) { 304 System.arraycopy(src, srcPos, dest, 0, 5); 305 } 306 307 // copyOfRange should compile to loads/stores 308 @Args(src=ArraySrc.SMALL) 309 static A[] m23() { 310 return Arrays.copyOfRange(small_a_src, 1, 4, A[].class); 311 } 312 313 static boolean m23_check(A[] src, A[] dest) { 314 boolean failure = false; 315 for (int i = 0; i < 3; i++) { 316 if (src[i+1] != dest[i]) { 317 System.out.println("Test m23 failed for " + i + " src[" + (i+1) +"]=" + dest[i] + ", dest[" + i + "]=" + dest[i]); 318 failure = true; 319 } 320 } 321 return failure; 322 } 323 324 // array copy should be compiled as loads/stores. Invoke then with 325 // incompatible array type to verify we don't allow a forbidden 326 // arraycopy to happen. 327 @Args(src=ArraySrc.SMALL) 328 static A[] m24(Object[] src) { 329 src[0] = src[0]; // force null check 330 A[] dest = new A[5]; 331 System.arraycopy(src, 0, dest, 0, 5); 332 return dest; 333 } 334 335 // overlapping array region with unknown src/dest offsets but 336 // length 1: compiled code doesn't need both forward and backward 337 // copies 338 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC, extra_args={0,1}) 339 static void m25(int[] src, int[] dest, int srcPos, int destPos) { 340 System.arraycopy(src, srcPos, dest, destPos, 1); 341 } 342 343 static boolean m25_check(int[] src, int[] dest) { 344 boolean failure = false; 345 if (dest[1] != src[0]) { 346 System.out.println("Test m10 failed for src[0]=" + src[0] + ", dest[1]=" + dest[1]); 347 return true; 348 } 349 return false; 350 } 351 352 final HashMap<String,Method> tests = new HashMap<>(); 353 { 354 for (Method m : this.getClass().getDeclaredMethods()) { 355 if (m.getName().matches("m[0-9]+(_check)?")) { 356 assert(Modifier.isStatic(m.getModifiers())) : m; 357 tests.put(m.getName(), m); 358 } 359 } 360 } 361 362 boolean success = true; 363 364 void doTest(String name) throws Exception { 365 Method m = tests.get(name); 366 Method m_check = tests.get(name + "_check"); 367 Class[] paramTypes = m.getParameterTypes(); 368 Object[] params = new Object[paramTypes.length]; 369 Class retType = m.getReturnType(); 370 boolean isIntArray = (retType.isPrimitive() && !retType.equals(Void.TYPE)) || 371 (retType.equals(Void.TYPE) && paramTypes[0].getComponentType().isPrimitive()) || 372 (retType.isArray() && retType.getComponentType().isPrimitive()); 373 374 Args args = m.getAnnotation(Args.class); 375 376 Object src = null; 377 switch(args.src()) { 378 case SMALL: { 379 if (isIntArray) { 380 src = small_int_src; 381 } else { 382 src = small_a_src; 383 } 384 break; 385 } 386 case LARGE: { 387 if (isIntArray) { 388 src = large_int_src; 389 } else { 390 src = large_a_src; 391 } 392 break; 393 } 394 case ZERO: { 395 assert isIntArray; 396 if (isIntArray) { 397 src = zero_int_src; 398 } else { 399 src = zero_a_src; 400 } 401 break; 402 } 403 } 404 405 for (int i = 0; i < 20000; i++) { 406 boolean failure = false; 407 408 int p = 0; 409 410 if (params.length > 0) { 411 if (isIntArray) { 412 params[0] = ((int[])src).clone(); 413 } else { 414 params[0] = ((A[])src).clone(); 415 } 416 p++; 417 } 418 419 if (params.length > 1) { 420 switch(args.dst()) { 421 case NEW: { 422 if (isIntArray) { 423 params[1] = new int[((int[])params[0]).length]; 424 } else { 425 params[1] = new A[((A[])params[0]).length]; 426 } 427 p++; 428 break; 429 } 430 case SRC: { 431 params[1] = params[0]; 432 p++; 433 break; 434 } 435 case NONE: break; 436 } 437 } 438 439 for (int j = 0; j < args.extra_args().length; j++) { 440 params[p+j] = args.extra_args()[j]; 441 } 442 443 Object res = m.invoke(null, params); 444 445 if (retType.isPrimitive() && !retType.equals(Void.TYPE)) { 446 int s = (int)res; 447 int sum = 0; 448 int[] int_res = (int[])src; 449 for (int j = 0; j < int_res.length; j++) { 450 sum += int_res[j]; 451 } 452 failure = (s != sum); 453 if (failure) { 454 System.out.println("Test " + name + " failed: result = " + s + " != " + sum); 455 } 456 } else { 457 Object dest = null; 458 if (!retType.equals(Void.TYPE)) { 459 dest = res; 460 } else { 461 dest = params[1]; 462 } 463 464 if (m_check != null) { 465 failure = (boolean)m_check.invoke(null, new Object[] { src, dest }); 466 } else { 467 if (isIntArray) { 468 int[] int_res = (int[])src; 469 int[] int_dest = (int[])dest; 470 for (int j = 0; j < int_res.length; j++) { 471 if (int_res[j] != int_dest[j]) { 472 System.out.println("Test " + name + " failed for " + j + " src[" + j +"]=" + int_res[j] + ", dest[" + j + "]=" + int_dest[j]); 473 failure = true; 474 } 475 } 476 } else { 477 Object[] object_res = (Object[])src; 478 Object[] object_dest = (Object[])dest; 479 for (int j = 0; j < object_res.length; j++) { 480 if (object_res[j] != object_dest[j]) { 481 System.out.println("Test " + name + " failed for " + j + " src[" + j +"]=" + object_res[j] + ", dest[" + j + "]=" + object_dest[j]); 482 failure = true; 483 } 484 } 485 } 486 } 487 } 488 489 if (failure) { 490 success = false; 491 break; 492 } 493 } 494 } 495 496 public static void main(String[] args) throws Exception { 497 for (int i = 0; i < small_a_src.length; i++) { 498 small_a_src[i] = new A(); 499 } 500 501 for (int i = 0; i < small_int_src.length; i++) { 502 small_int_src[i] = i; 503 } 504 505 for (int i = 0; i < large_int_src.length; i++) { 506 large_int_src[i] = i; 507 } 508 509 for (int i = 0; i < 5; i++) { 510 small_object_src[i] = new Object(); 511 } 512 513 TestArrayCopyAsLoadsStores test = new TestArrayCopyAsLoadsStores(); 514 515 test.doTest("m1"); 516 test.doTest("m2"); 517 test.doTest("m3"); 518 test.doTest("m4"); 519 test.doTest("m5"); 520 test.doTest("m6"); 521 test.doTest("m7"); 522 test.doTest("m8"); 523 test.doTest("m9"); 524 test.doTest("m10"); 525 test.doTest("m11"); 526 test.doTest("m12"); 527 test.doTest("m13"); 528 test.doTest("m14"); 529 test.doTest("m15"); 530 531 // make both branches of the If appear taken 532 for (int i = 0; i < 20000; i++) { 533 helper16(i); 534 } 535 536 test.doTest("m16"); 537 538 // load class B so type check in m17 would not be simple comparison 539 B b = new B(); 540 // make both branches of the If appear taken 541 for (int i = 0; i < 20000; i++) { 542 helper17_1(i); 543 } 544 545 test.doTest("m17"); 546 547 // make both branches of the If appear taken 548 for (int i = 0; i < 20000; i++) { 549 helper18_1(i); 550 } 551 test.doTest("m18"); 552 553 // make both branches of the If appear taken 554 for (int i = 0; i < 20000; i++) { 555 helper19(i); 556 } 557 558 // Compile 559 for (int i = 0; i < 20000; i++) { 560 m19(null, 0); 561 } 562 563 // force deopt 564 boolean m19_exception = false; 565 for (int i = 0; i < 10; i++) { 566 try { 567 m19(null, 1); 568 } catch(ArrayStoreException ase) { 569 m19_exception = true; 570 } 571 } 572 573 if (!m19_exception) { 574 System.out.println("Test m19: exception wasn't thrown"); 575 test.success = false; 576 } 577 578 test.doTest("m19"); 579 580 test.doTest("m20"); 581 test.doTest("m21"); 582 583 // Compile 584 int[] dst = new int[small_int_src.length]; 585 for (int i = 0; i < 20000; i++) { 586 m22(small_int_src, dst, 0); 587 } 588 589 // force deopt 590 for (int i = 0; i < 10; i++) { 591 try { 592 m22(small_int_src, dst, 5); 593 } catch(ArrayIndexOutOfBoundsException aioobe) {} 594 } 595 596 test.doTest("m22"); 597 test.doTest("m23"); 598 599 test.doTest("m24"); 600 boolean m24_exception = false; 601 try { 602 m24(small_object_src); 603 } catch(ArrayStoreException ase) { 604 m24_exception = true; 605 } 606 607 if (!m24_exception) { 608 System.out.println("Test m24: exception wasn't thrown"); 609 test.success = false; 610 } 611 612 test.doTest("m25"); 613 614 if (!test.success) { 615 throw new RuntimeException("some tests failed"); 616 } 617 } 618} 619