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 * @library / 29 * 30 * @run main/othervm -ea -XX:-BackgroundCompilation -XX:-UseOnStackReplacement 31 * -XX:CompileCommand=dontinline,compiler.arraycopy.TestArrayCopyAsLoadsStores::m* 32 * -XX:TypeProfileLevel=200 33 * compiler.arraycopy.TestArrayCopyAsLoadsStores 34 * @run main/othervm -ea -XX:-BackgroundCompilation -XX:-UseOnStackReplacement 35 * -XX:CompileCommand=dontinline,compiler.arraycopy.TestArrayCopyAsLoadsStores::m* 36 * -XX:TypeProfileLevel=200 37 * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressArrayCopyMacroNode 38 * compiler.arraycopy.TestArrayCopyAsLoadsStores 39 */ 40 41package compiler.arraycopy; 42 43import java.util.Arrays; 44 45public class TestArrayCopyAsLoadsStores extends TestArrayCopyUtils { 46 47 // array clone should be compiled as loads/stores 48 @Args(src=ArraySrc.SMALL) 49 static A[] m1() throws CloneNotSupportedException { 50 return (A[])small_a_src.clone(); 51 } 52 53 @Args(src=ArraySrc.SMALL) 54 static int[] m2() throws CloneNotSupportedException { 55 return (int[])small_int_src.clone(); 56 } 57 58 // new array allocation should be optimized out 59 @Args(src=ArraySrc.SMALL) 60 static int m3() throws CloneNotSupportedException { 61 int[] array_clone = (int[])small_int_src.clone(); 62 return array_clone[0] + array_clone[1] + array_clone[2] + 63 array_clone[3] + array_clone[4]; 64 } 65 66 // should not be compiled as loads/stores 67 @Args(src=ArraySrc.LARGE) 68 static int[] m4() throws CloneNotSupportedException { 69 return (int[])large_int_src.clone(); 70 } 71 72 // check that array of length 0 is handled correctly 73 @Args(src=ArraySrc.ZERO) 74 static int[] m5() throws CloneNotSupportedException { 75 return (int[])zero_int_src.clone(); 76 } 77 78 // array copy should be compiled as loads/stores 79 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NEW) 80 static void m6(int[] src, int[] dest) { 81 System.arraycopy(src, 0, dest, 0, 5); 82 } 83 84 // array copy should not be compiled as loads/stores 85 @Args(src=ArraySrc.LARGE, dst=ArrayDst.NEW) 86 static void m7(int[] src, int[] dest) { 87 System.arraycopy(src, 0, dest, 0, 10); 88 } 89 90 // array copy should be compiled as loads/stores 91 @Args(src=ArraySrc.SMALL) 92 static A[] m8(A[] src) { 93 src[0] = src[0]; // force null check 94 A[] dest = new A[5]; 95 System.arraycopy(src, 0, dest, 0, 5); 96 return dest; 97 } 98 99 // array copy should not be compiled as loads/stores: we would 100 // need to emit GC barriers 101 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NEW) 102 static void m9(A[] src, A[] dest) { 103 System.arraycopy(src, 0, dest, 0, 5); 104 } 105 106 // overlapping array regions: copy backward 107 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC) 108 static void m10(int[] src, int[] dest) { 109 System.arraycopy(src, 0, dest, 1, 4); 110 } 111 112 static boolean m10_check(int[] src, int[] dest) { 113 boolean failure = false; 114 for (int i = 0; i < 5; i++) { 115 int j = Math.max(i - 1, 0); 116 if (dest[i] != src[j]) { 117 System.out.println("Test m10 failed for " + i + " src[" + j +"]=" + src[j] + ", dest[" + i + "]=" + dest[i]); 118 failure = true; 119 } 120 } 121 return failure; 122 } 123 124 // overlapping array regions: copy forward 125 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC) 126 static void m11(int[] src, int[] dest) { 127 System.arraycopy(src, 1, dest, 0, 4); 128 } 129 130 static boolean m11_check(int[] src, int[] dest) { 131 boolean failure = false; 132 for (int i = 0; i < 5; i++) { 133 int j = Math.min(i + 1, 4); 134 if (dest[i] != src[j]) { 135 System.out.println("Test m11 failed for " + i + " src[" + j +"]=" + src[j] + ", dest[" + i + "]=" + dest[i]); 136 failure = true; 137 } 138 } 139 return failure; 140 } 141 142 // overlapping array region with unknown src/dest offsets: compiled code must include both forward and backward copies 143 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC, extra_args={0,1}) 144 static void m12(int[] src, int[] dest, int srcPos, int destPos) { 145 System.arraycopy(src, srcPos, dest, destPos, 4); 146 } 147 148 static boolean m12_check(int[] src, int[] dest) { 149 boolean failure = false; 150 for (int i = 0; i < 5; i++) { 151 int j = Math.max(i - 1, 0); 152 if (dest[i] != src[j]) { 153 System.out.println("Test m10 failed for " + i + " src[" + j +"]=" + src[j] + ", dest[" + i + "]=" + dest[i]); 154 failure = true; 155 } 156 } 157 return failure; 158 } 159 160 // Array allocation and copy should optimize out 161 @Args(src=ArraySrc.SMALL) 162 static int m13(int[] src) { 163 int[] dest = new int[5]; 164 System.arraycopy(src, 0, dest, 0, 5); 165 return dest[0] + dest[1] + dest[2] + dest[3] + dest[4]; 166 } 167 168 // Check that copy of length 0 is handled correctly 169 @Args(src=ArraySrc.ZERO, dst=ArrayDst.NEW) 170 static void m14(int[] src, int[] dest) { 171 System.arraycopy(src, 0, dest, 0, 0); 172 } 173 174 // copyOf should compile to loads/stores 175 @Args(src=ArraySrc.SMALL) 176 static A[] m15() { 177 return Arrays.copyOf(small_a_src, 5, A[].class); 178 } 179 180 static Object[] helper16(int i) { 181 Object[] arr = null; 182 if ((i%2) == 0) { 183 arr = small_a_src; 184 } else { 185 arr = small_object_src; 186 } 187 return arr; 188 } 189 190 // CopyOf may need subtype check 191 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 192 static A[] m16(A[] unused_src, int i) { 193 Object[] arr = helper16(i); 194 return Arrays.copyOf(arr, 5, A[].class); 195 } 196 197 static Object[] helper17_1(int i) { 198 Object[] arr = null; 199 if ((i%2) == 0) { 200 arr = small_a_src; 201 } else { 202 arr = small_object_src; 203 } 204 return arr; 205 } 206 207 static A[] helper17_2(Object[] arr) { 208 return Arrays.copyOf(arr, 5, A[].class); 209 } 210 211 // CopyOf may leverage type speculation 212 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 213 static A[] m17(A[] unused_src, int i) { 214 Object[] arr = helper17_1(i); 215 return helper17_2(arr); 216 } 217 218 static Object[] helper18_1(int i) { 219 Object[] arr = null; 220 if ((i%2) == 0) { 221 arr = small_a_src; 222 } else { 223 arr = small_object_src; 224 } 225 return arr; 226 } 227 228 static Object[] helper18_2(Object[] arr) { 229 return Arrays.copyOf(arr, 5, Object[].class); 230 } 231 232 // CopyOf should not attempt to use type speculation if it's not needed 233 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 234 static Object[] m18(A[] unused_src, int i) { 235 Object[] arr = helper18_1(i); 236 return helper18_2(arr); 237 } 238 239 static Object[] helper19(int i) { 240 Object[] arr = null; 241 if ((i%2) == 0) { 242 arr = small_a_src; 243 } else { 244 arr = small_object_src; 245 } 246 return arr; 247 } 248 249 // CopyOf may need subtype check. Test is run to make type check 250 // fail and cause deoptimization. Next compilation should not 251 // compile as loads/stores because the first compilation 252 // deoptimized. 253 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NONE, extra_args={0}) 254 static A[] m19(A[] unused_src, int i) { 255 Object[] arr = helper19(i); 256 return Arrays.copyOf(arr, 5, A[].class); 257 } 258 259 // copyOf for large array should not compile to loads/stores 260 @Args(src=ArraySrc.LARGE) 261 static A[] m20() { 262 return Arrays.copyOf(large_a_src, 10, A[].class); 263 } 264 265 // check zero length copyOf is handled correctly 266 @Args(src=ArraySrc.ZERO) 267 static A[] m21() { 268 return Arrays.copyOf(zero_a_src, 0, A[].class); 269 } 270 271 // Run with srcPos=0 for a 1st compile, then with incorrect value 272 // of srcPos to cause deoptimization, then with srcPos=0 for a 2nd 273 // compile. The 2nd compile shouldn't turn arraycopy into 274 // loads/stores because input arguments are no longer known to be 275 // valid. 276 @Args(src=ArraySrc.SMALL, dst=ArrayDst.NEW, extra_args={0}) 277 static void m22(int[] src, int[] dest, int srcPos) { 278 System.arraycopy(src, srcPos, dest, 0, 5); 279 } 280 281 // copyOfRange should compile to loads/stores 282 @Args(src=ArraySrc.SMALL) 283 static A[] m23() { 284 return Arrays.copyOfRange(small_a_src, 1, 4, A[].class); 285 } 286 287 static boolean m23_check(A[] src, A[] dest) { 288 boolean failure = false; 289 for (int i = 0; i < 3; i++) { 290 if (src[i+1] != dest[i]) { 291 System.out.println("Test m23 failed for " + i + " src[" + (i+1) +"]=" + dest[i] + ", dest[" + i + "]=" + dest[i]); 292 failure = true; 293 } 294 } 295 return failure; 296 } 297 298 // array copy should be compiled as loads/stores. Invoke then with 299 // incompatible array type to verify we don't allow a forbidden 300 // arraycopy to happen. 301 @Args(src=ArraySrc.SMALL) 302 static A[] m24(Object[] src) { 303 src[0] = src[0]; // force null check 304 A[] dest = new A[5]; 305 System.arraycopy(src, 0, dest, 0, 5); 306 return dest; 307 } 308 309 // overlapping array region with unknown src/dest offsets but 310 // length 1: compiled code doesn't need both forward and backward 311 // copies 312 @Args(src=ArraySrc.SMALL, dst=ArrayDst.SRC, extra_args={0,1}) 313 static void m25(int[] src, int[] dest, int srcPos, int destPos) { 314 System.arraycopy(src, srcPos, dest, destPos, 1); 315 } 316 317 static boolean m25_check(int[] src, int[] dest) { 318 boolean failure = false; 319 if (dest[1] != src[0]) { 320 System.out.println("Test m10 failed for src[0]=" + src[0] + ", dest[1]=" + dest[1]); 321 return true; 322 } 323 return false; 324 } 325 326 public static void main(String[] args) throws Exception { 327 TestArrayCopyAsLoadsStores test = new TestArrayCopyAsLoadsStores(); 328 329 test.doTest("m1"); 330 test.doTest("m2"); 331 test.doTest("m3"); 332 test.doTest("m4"); 333 test.doTest("m5"); 334 test.doTest("m6"); 335 test.doTest("m7"); 336 test.doTest("m8"); 337 test.doTest("m9"); 338 test.doTest("m10"); 339 test.doTest("m11"); 340 test.doTest("m12"); 341 test.doTest("m13"); 342 test.doTest("m14"); 343 test.doTest("m15"); 344 345 // make both branches of the If appear taken 346 for (int i = 0; i < 20000; i++) { 347 helper16(i); 348 } 349 350 test.doTest("m16"); 351 352 // load class B so type check in m17 would not be simple comparison 353 B b = new B(); 354 // make both branches of the If appear taken 355 for (int i = 0; i < 20000; i++) { 356 helper17_1(i); 357 } 358 359 test.doTest("m17"); 360 361 // make both branches of the If appear taken 362 for (int i = 0; i < 20000; i++) { 363 helper18_1(i); 364 } 365 test.doTest("m18"); 366 367 // make both branches of the If appear taken 368 for (int i = 0; i < 20000; i++) { 369 helper19(i); 370 } 371 372 // Compile 373 for (int i = 0; i < 20000; i++) { 374 m19(null, 0); 375 } 376 377 // force deopt 378 boolean m19_exception = false; 379 for (int i = 0; i < 10; i++) { 380 try { 381 m19(null, 1); 382 } catch(ArrayStoreException ase) { 383 m19_exception = true; 384 } 385 } 386 387 if (!m19_exception) { 388 System.out.println("Test m19: exception wasn't thrown"); 389 test.success = false; 390 } 391 392 test.doTest("m19"); 393 394 test.doTest("m20"); 395 test.doTest("m21"); 396 397 // Compile 398 int[] dst = new int[small_int_src.length]; 399 for (int i = 0; i < 20000; i++) { 400 m22(small_int_src, dst, 0); 401 } 402 403 // force deopt 404 for (int i = 0; i < 10; i++) { 405 try { 406 m22(small_int_src, dst, 5); 407 } catch(ArrayIndexOutOfBoundsException aioobe) {} 408 } 409 410 test.doTest("m22"); 411 test.doTest("m23"); 412 413 test.doTest("m24"); 414 boolean m24_exception = false; 415 try { 416 m24(small_object_src); 417 } catch(ArrayStoreException ase) { 418 m24_exception = true; 419 } 420 421 if (!m24_exception) { 422 System.out.println("Test m24: exception wasn't thrown"); 423 test.success = false; 424 } 425 426 test.doTest("m25"); 427 428 if (!test.success) { 429 throw new RuntimeException("some tests failed"); 430 } 431 } 432} 433