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 package compiler.valhalla.valuetypes;
  25 
  26 import jdk.test.lib.Asserts;
  27 
  28 /*
  29  * @test
  30  * @summary Test calls from {C1} to {C2, Interpreter}, and vice versa.
  31  * @library /testlibrary /test/lib /compiler/whitebox /
  32  * @requires os.simpleArch == "x64"
  33  * @compile -XDallowWithFieldOperator TestCallingConventionC1.java
  34  * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
  35  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  36  *                               -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla
  37  *                               compiler.valhalla.valuetypes.ValueTypeTest
  38  *                               compiler.valhalla.valuetypes.TestCallingConventionC1
  39  */
  40 public class TestCallingConventionC1 extends ValueTypeTest {
  41     public static final int C1 = COMP_LEVEL_SIMPLE;
  42     public static final int C2 = COMP_LEVEL_FULL_OPTIMIZATION;
  43 
  44     @Override
  45     public int getNumScenarios() {
  46         return 2;
  47     }
  48 
  49     @Override
  50     public String[] getVMParameters(int scenario) {
  51         switch (scenario) {
  52 
  53         // Default: both C1 and C2 are enabled, tierd compilation enabled
  54         case 0: return new String[] {"-XX:+EnableValhallaC1", "-XX:CICompilerCount=2"
  55                                      , "-XX:-CheckCompressedOops", "-XX:CompileCommand=print,*::test3*"
  56                                      };
  57         // Only C1. Tierd compilation disabled.
  58         case 1: return new String[] {"-XX:+EnableValhallaC1", "-XX:TieredStopAtLevel=1"};
  59         }
  60         return null;
  61     }
  62 
  63     public static void main(String[] args) throws Throwable {
  64         TestCallingConventionC1 test = new TestCallingConventionC1();
  65         test.run(args,
  66                  Point.class,
  67                  Functor.class,
  68                  Functor1.class,
  69                  Functor2.class,
  70                  Functor3.class,
  71                  Functor4.class);
  72     }
  73 
  74     static value class Point {
  75         final int x;
  76         final int y;
  77         public Point(int x, int y) {
  78             this.x = x;
  79             this.y = y;
  80         }
  81 
  82         @DontCompile // FIXME -- C1 can't handle incoming values yet
  83         public int func() {
  84             return x + y;
  85         }
  86     }
  87 
  88     static interface FunctorInterface {
  89         public int apply(Point p);
  90     }
  91 
  92     static class Functor implements FunctorInterface {
  93         @DontCompile // FIXME -- C1 can't handle incoming values yet
  94         @DontInline
  95         public int apply(Point p) {
  96             return p.func() + 0;
  97         }
  98     }
  99     static class Functor1 extends Functor {
 100         @DontCompile // FIXME -- C1 can't handle incoming values yet
 101         @DontInline
 102         public int apply(Point p) {
 103             return p.func() + 10000;
 104         }
 105     }
 106     static class Functor2 extends Functor {
 107         @DontCompile // FIXME -- C1 can't handle incoming values yet
 108         @DontInline
 109         public int apply(Point p) {
 110             return p.func() + 20000;
 111         }
 112     }
 113     static class Functor3 extends Functor {
 114         @DontCompile // FIXME -- C1 can't handle incoming values yet
 115         @DontInline
 116         public int apply(Point p) {
 117             return p.func() + 30000;
 118         }
 119     }
 120     static class Functor4 extends Functor {
 121         @DontCompile // FIXME -- C1 can't handle incoming values yet
 122         @DontInline
 123         public int apply(Point p) {
 124             return p.func() + 40000;
 125         }
 126     }
 127 
 128     static Functor functors[] = {
 129         new Functor(),
 130         new Functor1(),
 131         new Functor2(),
 132         new Functor3(),
 133         new Functor4()
 134     };
 135     static int counter = 0;
 136     static Functor getFunctor() {
 137         int n = (++ counter) % functors.length;
 138         return functors[n];
 139     }
 140 
 141     static Point pointField = new Point(123, 456);
 142 
 143     //**********************************************************************
 144     // PART 1 - C1 calls interpreted code
 145     //**********************************************************************
 146 
 147 
 148     //** C1 passes value to interpreter (static)
 149     @Test(compLevel = C1)
 150     public int test1() {
 151         return test1_helper(pointField);
 152     }
 153 
 154     @DontInline
 155     @DontCompile
 156     private static int test1_helper(Point p) {
 157         return p.func();
 158     }
 159 
 160     @DontCompile
 161     public void test1_verifier(boolean warmup) {
 162         int count = warmup ? 1 : 10;
 163         for (int i=0; i<count; i++) {
 164             int result = test1() + i;
 165             Asserts.assertEQ(result, pointField.func() + i);
 166         }
 167     }
 168 
 169 
 170     //** C1 passes value to interpreter (monomorphic)
 171     @Test(compLevel = C1)
 172     public int test2() {
 173         return test2_helper(pointField);
 174     }
 175 
 176     @DontInline
 177     @DontCompile
 178     private int test2_helper(Point p) {
 179         return p.func();
 180     }
 181 
 182     @DontCompile
 183     public void test2_verifier(boolean warmup) {
 184         int count = warmup ? 1 : 10;
 185         for (int i=0; i<count; i++) {
 186             int result = test2() + i;
 187             Asserts.assertEQ(result, pointField.func() + i);
 188         }
 189     }
 190 
 191     // C1 passes value to interpreter (megamorphic: vtable)
 192     @Test(compLevel = C1)
 193     public int test3(Functor functor) {
 194         return functor.apply(pointField);
 195     }
 196 
 197     @DontCompile
 198     public void test3_verifier(boolean warmup) {
 199         int count = warmup ? 1 : 100;
 200         for (int i=0; i<count; i++) {
 201             Functor functor = warmup ? functors[0] : getFunctor();
 202             int result = test3(functor) + i;
 203             Asserts.assertEQ(result, functor.apply(pointField) + i);
 204         }
 205     }
 206 
 207     // Same as test3, but compiled with C2. Test the hastable of VtableStubs
 208     @Test(compLevel = C2)
 209     public int test3b(Functor functor) {
 210         return functor.apply(pointField);
 211     }
 212 
 213     @DontCompile
 214     public void test3b_verifier(boolean warmup) {
 215         int count = warmup ? 1 : 100;
 216         for (int i=0; i<count; i++) {
 217             Functor functor = warmup ? functors[0] : getFunctor();
 218             int result = test3b(functor) + i;
 219             Asserts.assertEQ(result, functor.apply(pointField) + i);
 220         }
 221     }
 222 
 223     // C1 passes value to interpreter (megamorphic: itable)
 224     @Test(compLevel = C1)
 225     public int test4(FunctorInterface fi) {
 226         return fi.apply(pointField);
 227     }
 228 
 229     @DontCompile
 230     public void test4_verifier(boolean warmup) {
 231         int count = warmup ? 1 : 100;
 232         for (int i=0; i<count; i++) {
 233             Functor functor = warmup ? functors[0] : getFunctor();
 234             int result = test4(functor) + i;
 235             Asserts.assertEQ(result, functor.apply(pointField) + i);
 236         }
 237     }
 238 
 239     /* not working
 240 
 241     // Interpreter passes value to C1
 242     @Test(compLevel = C2)
 243     public int test2(Point p) {
 244         return p.x + p.y;
 245     }
 246 
 247     @DontCompile
 248     public void test2_verifier(boolean warmup) {
 249         int result = test2(pointField);
 250         int n = pointField.x + pointField.y;
 251         Asserts.assertEQ(result, n);
 252     }
 253 
 254     */
 255 
 256 
 257     /*
 258 
 259     // C1 passes value to C2
 260     @Test(compLevel = C1)
 261     public int test3() {
 262         return test3_helper(pointField);
 263     }
 264 
 265     @DontInline
 266     @ForceCompile(compLevel = C2)
 267     private static int test3_helper(Point p) {
 268         return p.x + p.y;
 269     }
 270 
 271     @DontCompile
 272     public void test3_verifier(boolean warmup) {
 273         int result = test3();
 274         int n = pointField.x + pointField.y;
 275         Asserts.assertEQ(result, n);
 276     }
 277 
 278     */
 279 }