1 /*
   2  * Copyright (c) 2015, 2018, 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 org.graalvm.compiler.core.test.tutorial;
  26 
  27 import java.lang.reflect.Method;
  28 import java.util.regex.Pattern;
  29 
  30 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
  31 import org.junit.Assert;
  32 import org.junit.Test;
  33 
  34 import jdk.vm.ci.code.InstalledCode;
  35 import jdk.vm.ci.code.InvalidInstalledCodeException;
  36 import jdk.vm.ci.meta.ResolvedJavaMethod;
  37 
  38 /**
  39  * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at
  40  * the examples in IGV (the graph visualization tool), use the {@code -Dgraal.Dump} and
  41  * {@code -Dgraal.MethodFilter} options. For example, run the first test case using
  42  *
  43  * <pre>
  44  * mx unittest -Dgraal.Dump= -Dgraal.MethodFilter=String.hashCode GraalTutorial#testStringHashCode
  45  * </pre>
  46  */
  47 public class GraalTutorial extends InvokeGraal {
  48 
  49     /*
  50      * Example for the Graal API: access the Graal API metadata object for a method.
  51      */
  52 
  53     @Test
  54     public void testGetBytecodes() throws NoSuchMethodException {
  55         Method reflectionMethod = String.class.getDeclaredMethod("hashCode");
  56         ResolvedJavaMethod method = metaAccess.lookupJavaMethod(reflectionMethod);
  57 
  58         /*
  59          * ResolvedJavaMethod provides all information that you want about a method, for example,
  60          * the bytecodes.
  61          */
  62         byte[] bytecodes = method.getCode();
  63 
  64         /*
  65          * BytecodeDisassembler shows you how to iterate bytecodes, how to access type information,
  66          * and more.
  67          */
  68         String disassembly = new BytecodeDisassembler().disassemble(method);
  69 
  70         /*
  71          * We don't want test cases to print any output, so we check the validity of the output
  72          * instead.
  73          */
  74         Pattern disassemblyLineRE = Pattern.compile(" *\\d+: [a-z][\\w_]+");
  75         for (String line : disassembly.split("\\n")) {
  76             Assert.assertTrue(line, disassemblyLineRE.matcher(line).find());
  77         }
  78         Assert.assertTrue(bytecodes.length > 0);
  79     }
  80 
  81     /*
  82      * A simple Graal compilation example: Compile the method String.hashCode()
  83      */
  84 
  85     @Test
  86     public void testStringHashCode() throws InvalidInstalledCodeException {
  87         int expectedResult = "Hello World".hashCode();
  88 
  89         InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode"));
  90 
  91         int result = (int) installedCode.executeVarargs("Hello World");
  92         Assert.assertEquals(expectedResult, result);
  93     }
  94 
  95     /*
  96      * Tutorial example for speculative optimizations.
  97      */
  98 
  99     int f1;
 100     int f2;
 101 
 102     public void speculativeOptimization(boolean flag) {
 103         f1 = 41;
 104         if (flag) {
 105             f2 = 42;
 106             return;
 107         }
 108         f2 = 43;
 109     }
 110 
 111     @Test
 112     public void testSpeculativeOptimization() throws InvalidInstalledCodeException {
 113         /*
 114          * Collect profiling information by running the method in the interpreter.
 115          */
 116 
 117         for (int i = 0; i < 10000; i++) {
 118             /* Execute several times so that enough profiling information gets collected. */
 119             speculativeOptimization(false);
 120         }
 121 
 122         /*
 123          * Warmup to collect profiling information is done, now we compile the method. Since the
 124          * value of "flag" was always false during the warmup, the compiled code speculates that the
 125          * value remains false.
 126          */
 127 
 128         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
 129         f1 = 0;
 130         f2 = 0;
 131         compiledMethod.executeVarargs(this, true);
 132         Assert.assertEquals(41, f1);
 133         Assert.assertEquals(42, f2);
 134 
 135         /*
 136          * We executed the compiled method with a "flag" value that triggered deoptimization (since
 137          * the warmup always used the different "flag" value). The interpreter updated the profiling
 138          * information, so the second compilation does not perform the speculative optimization.
 139          */
 140 
 141         compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
 142         f1 = 0;
 143         f2 = 0;
 144         compiledMethod.executeVarargs(this, false);
 145         Assert.assertEquals(41, f1);
 146         Assert.assertEquals(43, f2);
 147     }
 148 
 149     /*
 150      * Tutorial example for snippets and lowering.
 151      */
 152 
 153     public static int identityHashCodeUsage(Object obj) {
 154         return System.identityHashCode(obj);
 155     }
 156 
 157     @Test
 158     public void testIdentityHashCodeUsage() throws InvalidInstalledCodeException {
 159         Object a = new Object();
 160         int expectedResult = identityHashCodeUsage(a);
 161 
 162         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "identityHashCodeUsage"));
 163 
 164         int result = (int) compiledMethod.executeVarargs(a);
 165         Assert.assertEquals(expectedResult, result);
 166     }
 167 
 168     static class A {
 169     }
 170 
 171     static class B extends A {
 172     }
 173 
 174     public static int instanceOfUsage(Object obj) {
 175         if (obj instanceof A) {
 176             return 42;
 177         } else {
 178             return 0;
 179         }
 180     }
 181 
 182     @Test
 183     public void testInstanceOfUsage() throws InvalidInstalledCodeException {
 184         /*
 185          * Collect profiling information by running the method in the interpreter.
 186          */
 187 
 188         A a = new A();
 189         /* Allocate an (unused) instance of B so that the class B gets loaded. */
 190         @SuppressWarnings("unused")
 191         B b = new B();
 192         int expectedResult = instanceOfUsage(a);
 193         for (int i = 0; i < 10000; i++) {
 194             /* Execute several times so that enough profiling information gets collected. */
 195             instanceOfUsage(a);
 196         }
 197 
 198         /* Warmup to collect profiling information is done, now compile the method. */
 199 
 200         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage"));
 201 
 202         int result = (int) compiledMethod.executeVarargs(a);
 203         Assert.assertEquals(expectedResult, result);
 204     }
 205 
 206     /*
 207      * Tutorial example for intrinsic methods.
 208      */
 209 
 210     public static int intrinsicIntegerReverseBytes(int val) {
 211         return Integer.reverseBytes(val);
 212     }
 213 
 214     @Test
 215     public void testIntrinsicIntegerReverseBytes() throws InvalidInstalledCodeException {
 216         int input = 0x12345678;
 217         int expected = intrinsicIntegerReverseBytes(input);
 218 
 219         InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicIntegerReverseBytes"));
 220 
 221         int actual = (int) compiledMethod.executeVarargs(input);
 222         Assert.assertEquals(expected, actual);
 223     }
 224 }