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 
  41 package compiler.arraycopy;
  42 
  43 import java.util.Arrays;
  44 
  45 public 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 }