001/*
002 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.compiler.test.tutorial;
024
025import jdk.internal.jvmci.code.*;
026import jdk.internal.jvmci.meta.*;
027
028import org.junit.*;
029
030import com.oracle.graal.java.*;
031
032/**
033 * Examples for the Graal tutorial. Run them using the unittest harness of the mx script. To look at
034 * the examples in IGV (the graph visualization tool), use the options -G:Dump and -G:MethodFilter.
035 * For example, run the first test case using
036 *
037 * <pre>
038 * mx unittest -G:Dump= -G:MethodFilter=String.hashCode GraalTutorial#testStringHashCode
039 * </pre>
040 */
041public class GraalTutorial extends InvokeGraal {
042
043    /*
044     * Example for the Graal API: access the Graal API metadata object for a method.
045     */
046
047    @Test
048    public void testPrintBytecodes() {
049        ResolvedJavaMethod method = findMethod(String.class, "hashCode");
050
051        byte[] bytecodes = method.getCode();
052        Assert.assertNotNull(bytecodes);
053
054        System.out.println(new BytecodeDisassembler().disassemble(method));
055    }
056
057    /*
058     * A simple Graal compilation example: Compile the method String.hashCode()
059     */
060
061    @Test
062    public void testStringHashCode() throws InvalidInstalledCodeException {
063        int expectedResult = "Hello World".hashCode();
064
065        InstalledCode installedCode = compileAndInstallMethod(findMethod(String.class, "hashCode"));
066
067        int result = (int) installedCode.executeVarargs("Hello World");
068        Assert.assertEquals(expectedResult, result);
069    }
070
071    /*
072     * Tutorial example for speculative optimizations.
073     */
074
075    int f1;
076    int f2;
077
078    public void speculativeOptimization(boolean flag) {
079        f1 = 41;
080        if (flag) {
081            f2 = 42;
082            return;
083        }
084        f2 = 43;
085    }
086
087    @Test
088    public void testSpeculativeOptimization() throws InvalidInstalledCodeException {
089        /*
090         * Collect profiling information by running the method in the interpreter.
091         */
092
093        for (int i = 0; i < 10000; i++) {
094            /* Execute several times so that enough profiling information gets collected. */
095            speculativeOptimization(false);
096        }
097
098        /*
099         * Warmup to collect profiling information is done, now we compile the method. Since the
100         * value of "flag" was always false during the warmup, the compiled code speculates that the
101         * value remains false.
102         */
103
104        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
105        f1 = 0;
106        f2 = 0;
107        compiledMethod.executeVarargs(this, true);
108        Assert.assertEquals(41, f1);
109        Assert.assertEquals(42, f2);
110
111        /*
112         * We executed the compiled method with a "flag" value that triggered deoptimization (since
113         * the warmup always used the different "flag" value). The interpreter updated the profiling
114         * information, so the second compilation does not perform the speculative optimization.
115         */
116
117        compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "speculativeOptimization"));
118        f1 = 0;
119        f2 = 0;
120        compiledMethod.executeVarargs(this, false);
121        Assert.assertEquals(41, f1);
122        Assert.assertEquals(43, f2);
123    }
124
125    /*
126     * Tutorial example for snippets and lowering.
127     */
128
129    static class A {
130    }
131
132    static class B extends A {
133    }
134
135    public static int instanceOfUsage(Object obj) {
136        if (obj instanceof A) {
137            return 42;
138        } else {
139            return 0;
140        }
141    }
142
143    @Test
144    public void testInstanceOfUsage() throws InvalidInstalledCodeException {
145        /*
146         * Collect profiling information by running the method in the interpreter.
147         */
148
149        A a = new A();
150        /* Allocate an (unused) instance of B so that the class B gets loaded. */
151        @SuppressWarnings("unused")
152        B b = new B();
153        int expectedResult = instanceOfUsage(a);
154        for (int i = 0; i < 10000; i++) {
155            /* Execute several times so that enough profiling information gets collected. */
156            instanceOfUsage(a);
157        }
158
159        /* Warmup to collect profiling information is done, now compile the method. */
160
161        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "instanceOfUsage"));
162
163        int result = (int) compiledMethod.executeVarargs(a);
164        Assert.assertEquals(expectedResult, result);
165    }
166
167    /*
168     * Tutorial example for intrinsic methods.
169     */
170
171    public static double intrinsicUsage(double val) {
172        return Math.sin(val);
173    }
174
175    @Test
176    public void testIntrinsicUsage() throws InvalidInstalledCodeException {
177        double expectedResult = intrinsicUsage(42d);
178
179        InstalledCode compiledMethod = compileAndInstallMethod(findMethod(GraalTutorial.class, "intrinsicUsage"));
180
181        double result = (double) compiledMethod.executeVarargs(42d);
182        Assert.assertEquals(expectedResult, result, 0);
183    }
184}