1 /*
   2  * Copyright (c) 2017, 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 package compiler.valhalla.valuetypes;
  25 
  26 import jdk.test.lib.Asserts;
  27 
  28 /*
  29  * @test
  30  * @summary Test value type arrays
  31  * @library /testlibrary /test/lib /compiler/whitebox /
  32  * @requires os.simpleArch == "x64"
  33  * @modules java.base/jdk.experimental.bytecode
  34  *          java.base/jdk.experimental.value
  35  *          java.base/jdk.internal.misc:+open
  36  *          jdk.incubator.mvt
  37  * @compile -XDenableValueTypes TestArrays.java
  38  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  39  * @run main ClassFileInstaller jdk.test.lib.Platform
  40  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  41  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+AlwaysIncrementalInline
  42  *                   -XX:+EnableValhalla -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  43  *                   -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
  44  *                   compiler.valhalla.valuetypes.TestArrays
  45  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  46  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops
  47  *                   -XX:+EnableValhalla -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  48  *                   -XX:ValueFieldMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
  49  *                   compiler.valhalla.valuetypes.TestArrays
  50  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  51  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-UseCompressedOops
  52  *                   -XX:+EnableValhalla -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  53  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
  54  *                   -DVerifyIR=false compiler.valhalla.valuetypes.TestArrays
  55  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  56  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+AlwaysIncrementalInline
  57  *                   -XX:+EnableValhalla -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  58  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=0 -XX:ValueArrayElemMaxFlatOops=0
  59  *                   -DVerifyIR=false compiler.valhalla.valuetypes.TestArrays
  60  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  61  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI
  62  *                   -XX:+EnableValhalla -XX:+ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  63  *                   -XX:ValueFieldMaxFlatSize=0 -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
  64  *                   -DVerifyIR=false compiler.valhalla.valuetypes.TestArrays
  65  */
  66 public class TestArrays extends ValueTypeTest {
  67 
  68     public static void main(String[] args) throws Throwable {
  69         TestArrays test = new TestArrays();
  70         test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class);
  71     }
  72 
  73     // Helper methods
  74 
  75     protected long hash() {
  76         return hash(rI, rL);
  77     }
  78 
  79     protected long hash(int x, long y) {
  80         return MyValue1.createWithFieldsInline(x, y).hash();
  81     }
  82 
  83     // Test value type array creation and initialization
  84     @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD))
  85     @Test(valid = ValueTypeArrayFlattenOn)
  86     public MyValue1[] test1(int len) {
  87         MyValue1[] va = new MyValue1[len];
  88         for (int i = 0; i < len; ++i) {
  89             va[i] = MyValue1.createWithFieldsDontInline(rI, rL);
  90         }
  91         return va;
  92     }
  93 
  94     @DontCompile
  95     public void test1_verifier(boolean warmup) {
  96         int len = Math.abs(rI % 10);
  97         MyValue1[] va = test1(len);
  98         for (int i = 0; i < len; ++i) {
  99             Asserts.assertEQ(va[i].hash(), hash());
 100         }
 101     }
 102 
 103     // Test creation of a value type array and element access
 104     @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOOP + TRAP))
 105     @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOC + ALLOCA + LOOP + LOAD + LOADP + STORE + TRAP))
 106     public long test2() {
 107         MyValue1[] va = new MyValue1[1];
 108         va[0] = MyValue1.createWithFieldsInline(rI, rL);
 109         return va[0].hash();
 110     }
 111 
 112     @DontCompile
 113     public void test2_verifier(boolean warmup) {
 114         long result = test2();
 115         Asserts.assertEQ(result, hash());
 116     }
 117 
 118     // Test receiving a value type array from the interpreter,
 119     // updating its elements in a loop and computing a hash.
 120     @Test(failOn = (ALLOCA))
 121     public long test3(MyValue1[] va) {
 122         long result = 0;
 123         for (int i = 0; i < 10; ++i) {
 124             result += va[i].hash();
 125             va[i] = MyValue1.createWithFieldsInline(rI + 1, rL + 1);
 126         }
 127         return result;
 128     }
 129 
 130     @DontCompile
 131     public void test3_verifier(boolean warmup) {
 132         MyValue1[] va = new MyValue1[10];
 133         long expected = 0;
 134         for (int i = 0; i < 10; ++i) {
 135             va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i);
 136             expected += va[i].hash();
 137         }
 138         long result = test3(va);
 139         Asserts.assertEQ(expected, result);
 140         for (int i = 0; i < 10; ++i) {
 141             if (va[i].hash() != hash(rI + 1, rL + 1)) {
 142                 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1));
 143             }
 144         }
 145     }
 146 
 147     // Test returning a value type array received from the interpreter
 148     @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP)
 149     public MyValue1[] test4(MyValue1[] va) {
 150         return va;
 151     }
 152 
 153     @DontCompile
 154     public void test4_verifier(boolean warmup) {
 155         MyValue1[] va = new MyValue1[10];
 156         for (int i = 0; i < 10; ++i) {
 157             va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL + i);
 158         }
 159         va = test4(va);
 160         for (int i = 0; i < 10; ++i) {
 161             Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
 162         }
 163     }
 164 
 165     // Merge value type arrays created from two branches
 166     @Test
 167     public MyValue1[] test5(boolean b) {
 168         MyValue1[] va;
 169         if (b) {
 170             va = new MyValue1[5];
 171             for (int i = 0; i < 5; ++i) {
 172                 va[i] = MyValue1.createWithFieldsInline(rI, rL);
 173             }
 174         } else {
 175             va = new MyValue1[10];
 176             for (int i = 0; i < 10; ++i) {
 177                 va[i] = MyValue1.createWithFieldsInline(rI + i, rL + i);
 178             }
 179         }
 180         long sum = va[0].hashInterpreted();
 181         if (b) {
 182             va[0] = MyValue1.createWithFieldsDontInline(rI, sum);
 183         } else {
 184             va[0] = MyValue1.createWithFieldsDontInline(rI + 1, sum + 1);
 185         }
 186         return va;
 187     }
 188 
 189     @DontCompile
 190     public void test5_verifier(boolean warmup) {
 191         MyValue1[] va = test5(true);
 192         Asserts.assertEQ(va.length, 5);
 193         Asserts.assertEQ(va[0].hash(), hash(rI, hash()));
 194         for (int i = 1; i < 5; ++i) {
 195             Asserts.assertEQ(va[i].hash(), hash());
 196         }
 197         va = test5(false);
 198         Asserts.assertEQ(va.length, 10);
 199         Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1));
 200         for (int i = 1; i < 10; ++i) {
 201             Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
 202         }
 203     }
 204 
 205     // Test creation of value type array with single element
 206     @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD + LOOP + TRAP))
 207     @Test(valid = ValueTypeArrayFlattenOn, failOn = (ALLOCA + LOAD + LOOP + TRAP))
 208     public MyValue1 test6() {
 209         MyValue1[] va = new MyValue1[1];
 210         return va[0];
 211     }
 212 
 213     @DontCompile
 214     public void test6_verifier(boolean warmup) {
 215         MyValue1[] va = new MyValue1[1];
 216         MyValue1 v = test6();
 217         Asserts.assertEQ(v.hashPrimitive(), va[0].hashPrimitive());
 218     }
 219 
 220     // Test default initialization of value type arrays
 221     @Test(failOn = LOAD)
 222     public MyValue1[] test7(int len) {
 223         return new MyValue1[len];
 224     }
 225 
 226     @DontCompile
 227     public void test7_verifier(boolean warmup) {
 228         int len = Math.abs(rI % 10);
 229         MyValue1[] va = new MyValue1[len];
 230         MyValue1[] var = test7(len);
 231         for (int i = 0; i < len; ++i) {
 232             Asserts.assertEQ(va[i].hashPrimitive(), var[i].hashPrimitive());
 233         }
 234     }
 235 
 236     // Test creation of value type array with zero length
 237     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 238     public MyValue1[] test8() {
 239         return new MyValue1[0];
 240     }
 241 
 242     @DontCompile
 243     public void test8_verifier(boolean warmup) {
 244         MyValue1[] va = test8();
 245         Asserts.assertEQ(va.length, 0);
 246     }
 247 
 248     static MyValue1[] test9_va;
 249 
 250     // Test that value type array loaded from field has correct type
 251     @Test(failOn = (LOOP))
 252     public long test9() {
 253         return test9_va[0].hash();
 254     }
 255 
 256     @DontCompile
 257     public void test9_verifier(boolean warmup) {
 258         test9_va = new MyValue1[1];
 259         test9_va[0] = MyValue1.createWithFieldsInline(rI, rL);
 260         long result = test9();
 261         Asserts.assertEQ(result, hash());
 262     }
 263 
 264     // Multi-dimensional arrays
 265     @Test
 266     public MyValue1[][][] test10(int len1, int len2, int len3) {
 267         MyValue1[][][] arr = new MyValue1[len1][len2][len3];
 268         for (int i = 0; i < len1; i++) {
 269             for (int j = 0; j < len2; j++) {
 270                 for (int k = 0; k < len3; k++) {
 271                     arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i , rL + j + k);
 272                 }
 273             }
 274         }
 275         return arr;
 276     }
 277 
 278     @DontCompile
 279     public void test10_verifier(boolean warmup) {
 280         MyValue1[][][] arr = test10(2, 3, 4);
 281         for (int i = 0; i < 2; i++) {
 282             for (int j = 0; j < 3; j++) {
 283                 for (int k = 0; k < 4; k++) {
 284                     Asserts.assertEQ(arr[i][j][k].hash(), MyValue1.createWithFieldsDontInline(rI + i , rL + j + k).hash());
 285                 }
 286             }
 287         }
 288     }
 289 
 290     @Test
 291     public void test11(MyValue1[][][] arr, long[] res) {
 292         int l = 0;
 293         for (int i = 0; i < arr.length; i++) {
 294             for (int j = 0; j < arr[i].length; j++) {
 295                 for (int k = 0; k < arr[i][j].length; k++) {
 296                     res[l] = arr[i][j][k].hash();
 297                     l++;
 298                 }
 299             }
 300         }
 301     }
 302 
 303     @DontCompile
 304     public void test11_verifier(boolean warmup) {
 305         MyValue1[][][] arr = new MyValue1[2][3][4];
 306         long[] res = new long[2*3*4];
 307         long[] verif = new long[2*3*4];
 308         int l = 0;
 309         for (int i = 0; i < 2; i++) {
 310             for (int j = 0; j < 3; j++) {
 311                 for (int k = 0; k < 4; k++) {
 312                     arr[i][j][k] = MyValue1.createWithFieldsDontInline(rI + i, rL + j + k);
 313                     verif[l] = arr[i][j][k].hash();
 314                     l++;
 315                 }
 316             }
 317         }
 318         test11(arr, res);
 319         for (int i = 0; i < verif.length; i++) {
 320             Asserts.assertEQ(res[i], verif[i]);
 321         }
 322     }
 323 
 324     // Array load out of bounds (upper bound) at compile time
 325     @Test
 326     public int test12() {
 327         int arraySize = Math.abs(rI) % 10;;
 328         MyValue1[] va = new MyValue1[arraySize];
 329 
 330         for (int i = 0; i < arraySize; i++) {
 331             va[i] = MyValue1.createWithFieldsDontInline(rI + 1, rL);
 332         }
 333 
 334         try {
 335             return va[arraySize + 1].x;
 336         } catch (ArrayIndexOutOfBoundsException e) {
 337             return rI;
 338         }
 339     }
 340 
 341     public void test12_verifier(boolean warmup) {
 342         Asserts.assertEQ(test12(), rI);
 343     }
 344 
 345     // Array load  out of bounds (lower bound) at compile time
 346     @Test
 347     public int test13() {
 348         int arraySize = Math.abs(rI) % 10;;
 349         MyValue1[] va = new MyValue1[arraySize];
 350 
 351         for (int i = 0; i < arraySize; i++) {
 352             va[i] = MyValue1.createWithFieldsDontInline(rI + i, rL);
 353         }
 354 
 355         try {
 356             return va[-arraySize].x;
 357         } catch (ArrayIndexOutOfBoundsException e) {
 358             return rI;
 359         }
 360     }
 361 
 362     public void test13_verifier(boolean warmup) {
 363         Asserts.assertEQ(test13(), rI);
 364     }
 365 
 366     // Array load out of bound not known to compiler (both lower and upper bound)
 367     @Test
 368     public int test14(MyValue1[] va, int index)  {
 369         return va[index].x;
 370     }
 371 
 372     public void test14_verifier(boolean warmup) {
 373         int arraySize = Math.abs(rI) % 10;
 374         MyValue1[] va = new MyValue1[arraySize];
 375 
 376         for (int i = 0; i < arraySize; i++) {
 377             va[i] = MyValue1.createWithFieldsDontInline(rI, rL);
 378         }
 379 
 380         int result;
 381         for (int i = -20; i < 20; i++) {
 382             try {
 383                 result = test14(va, i);
 384             } catch (ArrayIndexOutOfBoundsException e) {
 385                 result = rI;
 386             }
 387             Asserts.assertEQ(result, rI);
 388         }
 389     }
 390 
 391     // Array store out of bounds (upper bound) at compile time
 392     @Test
 393     public int test15() {
 394         int arraySize = Math.abs(rI) % 10;;
 395         MyValue1[] va = new MyValue1[arraySize];
 396 
 397         try {
 398             for (int i = 0; i <= arraySize; i++) {
 399                 va[i] = MyValue1.createWithFieldsDontInline(rI + 1, rL);
 400             }
 401             return rI - 1;
 402         } catch (ArrayIndexOutOfBoundsException e) {
 403             return rI;
 404         }
 405     }
 406 
 407     public void test15_verifier(boolean warmup) {
 408         Asserts.assertEQ(test15(), rI);
 409     }
 410 
 411     // Array store out of bounds (lower bound) at compile time
 412     @Test
 413     public int test16() {
 414         int arraySize = Math.abs(rI) % 10;;
 415         MyValue1[] va = new MyValue1[arraySize];
 416 
 417         try {
 418             for (int i = -1; i <= arraySize; i++) {
 419                 va[i] = MyValue1.createWithFieldsDontInline(rI + 1, rL);
 420             }
 421             return rI - 1;
 422         } catch (ArrayIndexOutOfBoundsException e) {
 423             return rI;
 424         }
 425     }
 426 
 427     public void test16_verifier(boolean warmup) {
 428         Asserts.assertEQ(test16(), rI);
 429     }
 430 
 431     // Array store out of bound not known to compiler (both lower and upper bound)
 432     @Test
 433     public int test17(MyValue1[] va, int index, MyValue1 vt)  {
 434         va[index] = vt;
 435         return va[index].x;
 436     }
 437 
 438     @DontCompile
 439     public void test17_verifier(boolean warmup) {
 440         int arraySize = Math.abs(rI) % 10;
 441         MyValue1[] va = new MyValue1[arraySize];
 442 
 443         for (int i = 0; i < arraySize; i++) {
 444             va[i] = MyValue1.createWithFieldsDontInline(rI, rL);
 445         }
 446 
 447         MyValue1 vt = MyValue1.createWithFieldsDontInline(rI + 1, rL);
 448         int result;
 449         for (int i = -20; i < 20; i++) {
 450             try {
 451                 result = test17(va, i, vt);
 452             } catch (ArrayIndexOutOfBoundsException e) {
 453                 result = rI + 1;
 454             }
 455             Asserts.assertEQ(result, rI + 1);
 456         }
 457 
 458         for (int i = 0; i < arraySize; i++) {
 459             Asserts.assertEQ(va[i].x, rI + 1);
 460         }
 461     }
 462 }