1 /*
   2  * Copyright (c) 2016, 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 // TODO add bugid and summary
  25 
  26 /*
  27  * @test
  28  * @library /testlibrary /test/lib /compiler/whitebox /
  29  * @build compiler.valhalla.valuetypes.ValueTypeTestBench
  30  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  31  * @run main ClassFileInstaller jdk.test.lib.Platform
  32  * @run main/othervm -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  33  *                   compiler.valhalla.valuetypes.ValueTypeTestBench
  34  */
  35 
  36 package compiler.valhalla.valuetypes;
  37 
  38 import compiler.whitebox.CompilerWhiteBoxTest;
  39 import jdk.internal.misc.Unsafe;
  40 import jdk.test.lib.Asserts;
  41 import jdk.test.lib.Platform;
  42 import jdk.test.lib.ProcessTools;
  43 import jdk.test.lib.OutputAnalyzer;
  44 import sun.hotspot.WhiteBox;
  45 
  46 import java.lang.annotation.Retention;
  47 import java.lang.annotation.RetentionPolicy;
  48 import java.lang.reflect.Method;
  49 import java.util.ArrayList;
  50 import java.util.Hashtable;
  51 
  52 @Retention(RetentionPolicy.RUNTIME)
  53 @interface Test {
  54     String[] nodeBlacklist() default {};
  55 }
  56 
  57 @Retention(RetentionPolicy.RUNTIME)
  58 @interface ForceInline { }
  59 
  60 @Retention(RetentionPolicy.RUNTIME)
  61 @interface DontInline { }
  62 
  63 @Retention(RetentionPolicy.RUNTIME)
  64 @interface Exclude { }
  65 
  66 public class ValueTypeTestBench {
  67     private static final boolean PRINT_GRAPH = true;
  68     private static final String ALLOC = "_new_instance_Java";
  69     private static final String LOADI = "LoadI";
  70     private static final String LOADL = "LoadL";
  71     private static final String LOADD = "LoadD";
  72 
  73     // ========== Test definitions ==========
  74 
  75     @Test(nodeBlacklist = {ALLOC})
  76     public long test1() {
  77         MyValue v = MyValue.createDontInline(1, 2, 3);
  78         return v.x + v.y + (long) v.z;
  79     }
  80 
  81     @Exclude
  82     public void test1_verifier() {
  83         long result = test1();
  84         Asserts.assertEQ(result, 6L);
  85     }
  86 
  87     @Test(nodeBlacklist = {ALLOC, LOADI, LOADL, LOADD})
  88     public long test2() {
  89         MyValue v = MyValue.createInline(1, 2, 3);
  90         return v.x + v.y + (long) v.z;
  91     }
  92 
  93     @Exclude
  94     public void test2_verifier() {
  95         long result = test2();
  96         Asserts.assertEQ(result, 6L);
  97     }
  98 
  99     @Test(nodeBlacklist = {ALLOC})
 100     public long test3(MyValue v) {
 101         return v.x + v.y + (long) v.z;
 102     }
 103 
 104     @Exclude
 105     public void test3_verifier() {
 106         MyValue v = MyValue.createDontInline(1, 2, 3);
 107         long result = test3(v);
 108         Asserts.assertEQ(result, 6L);
 109     }
 110 
 111     @Test(nodeBlacklist = {ALLOC, LOADI, LOADL, LOADD})
 112     public MyValue test4(MyValue v) {
 113         return v;
 114     }
 115 
 116     @Exclude
 117     public void test4_verifier() {
 118         MyValue v1 = MyValue.createDontInline(1, 2, 3);
 119         MyValue v2 = test4(v1);
 120         Asserts.assertEQ(v1.x, v2.x);
 121         Asserts.assertEQ(v1.y, v2.y);
 122         Asserts.assertEQ(v1.z, v2.z);
 123     }
 124 
 125     @Test(nodeBlacklist = {ALLOC, LOADI, LOADL, LOADD})
 126     public long test5() {
 127         MyValue v = MyValue.createInline(1, 2, 3);
 128         return test5Inline(v);
 129     }
 130 
 131     @ForceInline
 132     public long test5Inline(MyValue v) {
 133         return v.x + v.y + (long) v.z;
 134     }
 135 
 136     @Exclude
 137     public void test5_verifier() {
 138         long result = test5();
 139         Asserts.assertEQ(result, 6L);
 140     }
 141 
 142     @Test(nodeBlacklist = {LOADI, LOADL, LOADD})
 143     public MyValue test6(int x, long y, double z) {
 144         return MyValue.createInline(x, y, z);
 145     }
 146 
 147     @Exclude
 148     public void test6_verifier() {
 149         MyValue v = test6(1, 2, 3);
 150         long result = v.x + v.y + (long) v.z;
 151         Asserts.assertEQ(result, 6L);
 152     }
 153 
 154 
 155     // ========== Test infrastructure ==========
 156 
 157     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
 158     private static final int COMP_LEVEL_ANY = -1;
 159     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 160     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
 161     private static final int WARMUP = 10;
 162 
 163     static {
 164         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
 165             if (m.isAnnotationPresent(Test.class)) {
 166                 tests.put(m.getName(), m);
 167             }
 168         }
 169     }
 170 
 171     public static void main(String[] args) throws Throwable {
 172         if (args.length == 0) {
 173             OutputAnalyzer oa = ProcessTools.executeTestJvm("-noverify",
 174                     "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
 175                     "-XX:-TieredCompilation", "-XX:-BackgroundCompilation", "-XX:-UseOnStackReplacement",
 176                     "-XX:CompileCommand=quiet", "-XX:+PrintCompilation", "-XX:+PrintIdeal",
 177                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
 178                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue::*",
 179                     ValueTypeTestBench.class.getName(), "run");
 180             String output = oa.getOutput();
 181             oa.shouldHaveExitValue(0);
 182             parseOutput(output);
 183         } else {
 184             ValueTypeTestBench bench = new ValueTypeTestBench();
 185             bench.run();
 186         }
 187     }
 188 
 189     public static void parseOutput(String output) throws Exception {
 190         String split = ValueTypeTestBench.class.getCanonicalName() + "::";
 191         for (String graph : output.split(split)) {
 192             String[] lines = graph.split("\\n");
 193             String testName = lines[0].split(" ")[0];
 194             Method test = tests.get(testName);
 195             if (test == null) {
 196                 // Skip helper methods
 197                 continue;
 198             }
 199             Test anno = test.getAnnotation(Test.class);
 200             String[] blacklist = anno.nodeBlacklist();
 201             for (String black : blacklist) {
 202                 if (graph.contains(black)) {
 203                     System.out.println("\nGraph for " + graph);
 204                     throw new RuntimeException("Graph for test '" + testName + "' contains blacklisted node '" +  black + "' ");
 205                 }
 206             }
 207             if (PRINT_GRAPH) {
 208                 System.out.println("\nGraph for " + graph);
 209             }
 210             tests.remove(testName);
 211             System.out.println(testName + " passed");
 212         }
 213         // Check if all tests were compiled
 214         if (tests.size() != 0) {
 215             for (String name : tests.keySet()) {
 216                 System.out.println("Test '" + name + "' not compiled!");
 217             }
 218             throw new RuntimeException("Not all tests were compiled");
 219         }
 220     }
 221 
 222     public void setup(Method[] methods) {
 223         for (Method m : methods) {
 224             if (m.isAnnotationPresent(Test.class)) {
 225                 // Don't inline tests
 226                 WHITE_BOX.testSetDontInlineMethod(m, true);
 227             }
 228             if (m.isAnnotationPresent(Exclude.class)) {
 229                 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, true);
 230                 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_ANY, false);
 231             }
 232             if (m.isAnnotationPresent(ForceInline.class)) {
 233                 WHITE_BOX.testSetForceInlineMethod(m, true);
 234             } else if (m.isAnnotationPresent(DontInline.class)) {
 235                 WHITE_BOX.testSetDontInlineMethod(m, true);
 236             }
 237         }
 238     }
 239 
 240     public void run() throws Exception {
 241         setup(this.getClass().getDeclaredMethods());
 242         setup(MyValue.class.getDeclaredMethods());
 243 
 244         // Execute tests
 245         for (Method test : tests.values()) {
 246             Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier");
 247             // Warmup using verifier method
 248             for (int i = 0; i < WARMUP; ++i) {
 249                 verifier.invoke(this);
 250             }
 251             // Trigger compilation
 252             WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
 253             // Check result
 254             verifier.invoke(this);
 255         }
 256     }
 257 }
 258 
 259 __ByValue final class MyValue {
 260     final int x;
 261     final long y;
 262     final double z;
 263 
 264     private MyValue(int x, long y, double z) {
 265         this.x = x;
 266         this.y = y;
 267         this.z = z;
 268     }
 269 
 270     @DontInline
 271     public static MyValue createDontInline(int x, long y, double z) {
 272         return __Make MyValue(x, y, z);
 273     }
 274 
 275     @ForceInline
 276     public static MyValue createInline(int x, long y, double z) {
 277         return __Make MyValue(x, y, z);
 278     }
 279 }