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 }