1 /*
   2  * Copyright (c) 2019, 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 package compiler.valhalla.valuetypes;
  26 
  27 import java.lang.invoke.*;
  28 import java.lang.reflect.Method;
  29 import java.util.Arrays;
  30 
  31 import jdk.experimental.value.MethodHandleBuilder;
  32 import jdk.test.lib.Asserts;
  33 
  34 /*
  35  * @test
  36  * @summary Verify that C1 performs escape analysis before optimizing withfield bytecode to putfield.
  37  * @modules java.base/jdk.experimental.value
  38  * @library /testlibrary /test/lib /compiler/whitebox /
  39  * @requires os.simpleArch == "x64"
  40  * @compile -XDallowWithFieldOperator TestWithfieldC1.java
  41  * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
  42  * @run main/othervm/timeout=300 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  43  *                               -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI
  44  *                               compiler.valhalla.valuetypes.ValueTypeTest
  45  *                               compiler.valhalla.valuetypes.TestWithfieldC1
  46  */
  47 public class TestWithfieldC1 extends ValueTypeTest {
  48     public static final int C1 = COMP_LEVEL_SIMPLE;
  49     public static final int C2 = COMP_LEVEL_FULL_OPTIMIZATION;
  50 
  51     public static void main(String[] args) throws Throwable {
  52         TestWithfieldC1 test = new TestWithfieldC1();
  53         test.run(args, FooValue.class);
  54     }
  55 
  56     @Override
  57     public int getNumScenarios() {
  58         return 5;
  59     }
  60 
  61     @Override
  62     public String[] getVMParameters(int scenario) {
  63         switch (scenario) {
  64         case 0: return new String[] { // C1 only
  65                 "-XX:+EnableValhallaC1",
  66                 "-XX:TieredStopAtLevel=1",
  67             };
  68         case 1: return new String[] { // C2 only. (Make sure the tests are correctly written)
  69                 "-XX:-EnableValhallaC1",
  70                 "-XX:TieredStopAtLevel=4",
  71             };
  72         case 2: return new String[] { // interpreter only
  73                 "-Xint",
  74             };
  75         case 3: return new String[] {
  76                 // Xcomp Only C1.
  77                 "-XX:+EnableValhallaC1",
  78                 "-XX:TieredStopAtLevel=1",
  79                 "-Xcomp",
  80             };
  81         case 4: return new String[] {
  82                 // Xcomp Only C2.
  83                 "-XX:-EnableValhallaC1",
  84                 "-XX:TieredStopAtLevel=4",
  85                 "-Xcomp",
  86             };
  87         }
  88         return null;
  89     }
  90 
  91     static FooValue? foo_static;
  92     static FooValue? foo_static_arr[] = new FooValue?[1];
  93     FooValue? foo_instance;
  94 
  95     @DontInline
  96     static void set_foo_static_if_null(FooValue v) {
  97         if (foo_static == null) {
  98             foo_static = v;
  99         }
 100     }
 101 
 102     static inline class FooValue {
 103         public int x = 0, y = 0;
 104 
 105         @ForceInline
 106         static FooValue test1() {
 107             FooValue v = FooValue.default;
 108 
 109             v = __WithField(v.x, 1);
 110             v = __WithField(v.y, 1);
 111             foo_static = v;
 112 
 113             v = __WithField(v.x, 2);
 114             v = __WithField(v.y, 2);
 115             return v;
 116         }
 117 
 118         @ForceInline
 119         static FooValue test3() {
 120             FooValue v = FooValue.default;
 121 
 122             v = __WithField(v.x, 1);
 123             v = __WithField(v.y, 1);
 124             set_foo_static_if_null(v);
 125 
 126             v = __WithField(v.x, 2);
 127             v = __WithField(v.y, 2);
 128             return v;
 129         }
 130 
 131         @ForceInline
 132         static FooValue test4() {
 133             FooValue v = FooValue.default;
 134             for (int i=1; i<=2; i++) {
 135                 v = __WithField(v.x, i);
 136                 v = __WithField(v.y, i);
 137                 set_foo_static_if_null(v);
 138             }
 139 
 140             return v;
 141         }
 142 
 143         @ForceInline
 144         static FooValue test5() {
 145             FooValue v1 = FooValue.default;
 146             FooValue v2 = FooValue.default;
 147             v2 = v1;
 148 
 149             v1 = __WithField(v1.x, 1);
 150             v1 = __WithField(v1.y, 1);
 151             set_foo_static_if_null(v1);
 152 
 153             v2 = __WithField(v2.x, 2);
 154             v2 = __WithField(v2.y, 2);
 155 
 156             return v2;
 157         }
 158 
 159         @ForceInline
 160         static FooValue test6() {
 161             FooValue v = FooValue.default;
 162 
 163             v = __WithField(v.x, 1);
 164             v = __WithField(v.y, 1);
 165             foo_static_arr[0] = v;
 166 
 167             v = __WithField(v.x, 2);
 168             v = __WithField(v.y, 2);
 169             return v;
 170         }
 171 
 172 
 173         @ForceInline
 174         static FooValue test7() {
 175             FooValue v1 = FooValue.default;
 176             FooValue v2 = FooValue.default;
 177             v2 = v1;
 178 
 179             v1 = __WithField(v1.x, 1);
 180             v1 = __WithField(v1.y, 1);
 181 
 182             v2 = __WithField(v2.x, 2);
 183             v2 = __WithField(v2.y, 2);
 184 
 185             return v1;
 186         }
 187 
 188         @ForceInline
 189         static FooValue test8() {
 190             FooValue v1 = FooValue.default;
 191 
 192             v1 = __WithField(v1.x, 1);
 193             v1 = __WithField(v1.y, 1);
 194 
 195             v1.non_static_method();
 196 
 197             v1 = __WithField(v1.x, 2);
 198             v1 = __WithField(v1.y, 2);
 199 
 200             return v1;
 201         }
 202 
 203 
 204         @DontInline
 205         private void non_static_method() {
 206             set_foo_static_if_null(this);
 207         }
 208     }
 209 
 210     static void validate_foo_static_and(FooValue v) {
 211         Asserts.assertEQ(foo_static.x, 1);
 212         Asserts.assertEQ(foo_static.y, 1);
 213         Asserts.assertEQ(v.x, 2);
 214         Asserts.assertEQ(v.y, 2);
 215     }
 216 
 217     // escape with putstatic
 218     @Test(compLevel=C1)
 219     public FooValue test1() {
 220         return FooValue.test1();
 221     }
 222 
 223     @DontCompile
 224     public void test1_verifier(boolean warmup) {
 225         FooValue v = test1();
 226         validate_foo_static_and(v);
 227     }
 228 
 229     // escape with putfield
 230     @Test(compLevel=C1)
 231     public FooValue test2() {
 232         FooValue v = FooValue.default;
 233 
 234         v = __WithField(v.x, 1);
 235         v = __WithField(v.y, 1);
 236         foo_instance = v;
 237 
 238         v = __WithField(v.x, 2);
 239         v = __WithField(v.y, 2);
 240         return v;
 241     }
 242 
 243     @DontCompile
 244     public void test2_verifier(boolean warmup) {
 245         foo_instance = null;
 246         FooValue v = test2();
 247         Asserts.assertEQ(foo_instance.x, 1);
 248         Asserts.assertEQ(foo_instance.y, 1);
 249         Asserts.assertEQ(v.x, 2);
 250         Asserts.assertEQ(v.y, 2);
 251     }
 252 
 253     // escape with function call
 254     @Test(compLevel=C1)
 255     public FooValue test3() {
 256         return FooValue.test3();
 257     }
 258 
 259     @DontCompile
 260     public void test3_verifier(boolean warmup) {
 261         foo_static = null;
 262         FooValue v = test3();
 263         validate_foo_static_and(v);
 264     }
 265 
 266     // escape and then branch backwards
 267     @Test(compLevel=C1)
 268     public FooValue test4() {
 269         return FooValue.test4();
 270     }
 271 
 272     @DontCompile
 273     public void test4_verifier(boolean warmup) {
 274         foo_static = null;
 275         FooValue v = test4();
 276         validate_foo_static_and(v);
 277     }
 278 
 279     // escape using a different local variable
 280     @Test(compLevel=C1)
 281     public FooValue test5() {
 282         return FooValue.test5();
 283     }
 284 
 285     @DontCompile
 286     public void test5_verifier(boolean warmup) {
 287         foo_static = null;
 288         FooValue v = test5();
 289         validate_foo_static_and(v);
 290     }
 291 
 292     // escape using aastore
 293     @Test(compLevel=C1)
 294     public FooValue test6() {
 295         return FooValue.test6();
 296     }
 297 
 298     @DontCompile
 299     public void test6_verifier(boolean warmup) {
 300         foo_static_arr[0] = null;
 301         FooValue v = test6();
 302         Asserts.assertEQ(foo_static_arr[0].x, 1);
 303         Asserts.assertEQ(foo_static_arr[0].y, 1);
 304         Asserts.assertEQ(v.x, 2);
 305         Asserts.assertEQ(v.y, 2);
 306     }
 307 
 308     // Copying a value into different local slots -- disable withfield optimization
 309     @Test(compLevel=C1)
 310     public FooValue test7() {
 311         return FooValue.test7();
 312     }
 313 
 314     @DontCompile
 315     public void test7_verifier(boolean warmup) {
 316         FooValue v = test7();
 317         Asserts.assertEQ(v.x, 1);
 318         Asserts.assertEQ(v.y, 1);
 319     }
 320 
 321     // escape by invoking non-static method
 322     @Test(compLevel=C1)
 323     public FooValue test8() {
 324         return FooValue.test8();
 325     }
 326 
 327     @DontCompile
 328     public void test8_verifier(boolean warmup) {
 329         foo_static = null;
 330         FooValue v = test8();
 331         validate_foo_static_and(v);
 332     }
 333 }