1 /*
   2  * Copyright (c) 2016, 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 package org.graalvm.compiler.api.directives.test;
  24 
  25 import java.io.ByteArrayOutputStream;
  26 import java.lang.reflect.Method;
  27 import java.util.Formatter;
  28 import java.util.HashMap;
  29 import java.util.Map;
  30 
  31 import org.junit.Assert;
  32 import org.junit.Test;
  33 
  34 import com.google.monitoring.runtime.instrumentation.common.com.google.common.base.Objects;
  35 import org.graalvm.compiler.api.directives.GraalDirectives;
  36 import org.graalvm.compiler.core.common.GraalOptions;
  37 import org.graalvm.compiler.core.test.GraalCompilerTest;
  38 import org.graalvm.compiler.debug.Debug;
  39 import org.graalvm.compiler.debug.Debug.Scope;
  40 import org.graalvm.compiler.nodes.StructuredGraph;
  41 import org.graalvm.compiler.options.OptionValue;
  42 import org.graalvm.compiler.options.OptionValue.OverrideScope;
  43 import org.graalvm.compiler.printer.IdealGraphPrinter;
  44 
  45 import jdk.vm.ci.code.CodeCacheProvider;
  46 import jdk.vm.ci.code.InstalledCode;
  47 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod;
  48 import jdk.vm.ci.meta.ResolvedJavaMethod;
  49 
  50 public class RootNameDirectiveTest extends GraalCompilerTest {
  51 
  52     public RootNameDirectiveTest() {
  53         HotSpotResolvedJavaMethod rootNameAtCalleeSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameAtCalleeSnippet");
  54         rootNameAtCalleeSnippet.shouldBeInlined();
  55 
  56         HotSpotResolvedJavaMethod rootNameWithinInstrumentationSnippet = (HotSpotResolvedJavaMethod) getResolvedJavaMethod(RootNameDirectiveTest.class, "rootNameWithinInstrumentationSnippet");
  57         rootNameWithinInstrumentationSnippet.shouldBeInlined();
  58     }
  59 
  60     private static String toString(ResolvedJavaMethod method) {
  61         return method.getDeclaringClass().toJavaName() + "." + method.getName() + method.getSignature().toMethodDescriptor();
  62     }
  63 
  64     public static String rootNameSnippet() {
  65         return GraalDirectives.rootName();
  66     }
  67 
  68     @Test
  69     public void testRootName() {
  70         ResolvedJavaMethod method = getResolvedJavaMethod("rootNameSnippet");
  71         executeExpected(method, null); // ensure the method is fully resolved
  72         // The target snippet is already the root method. We expect the name of the target snippet
  73         // is returned.
  74         InstalledCode code = getCode(method);
  75         try {
  76             Result result = new Result(code.executeVarargs(), null);
  77             assertEquals(new Result(toString(method), null), result);
  78         } catch (Throwable e) {
  79             throw new AssertionError(e);
  80         }
  81     }
  82 
  83     public static String rootNameAtCalleeSnippet() {
  84         return GraalDirectives.rootName();
  85     }
  86 
  87     public static String callerSnippet() {
  88         return rootNameAtCalleeSnippet();
  89     }
  90 
  91     @Test
  92     public void testRootNameAtCallee() {
  93         ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet");
  94         executeExpected(method, null); // ensure the method is fully resolved
  95         // The target snippet is the compilation root of rootNameAtCalleeSnippet() because the later
  96         // will be inlined. We expect the name of the target snippet is returned.
  97         InstalledCode code = getCode(method);
  98         try {
  99             Result result = new Result(code.executeVarargs(), null);
 100             assertEquals(new Result(toString(method), null), result);
 101         } catch (Throwable e) {
 102             throw new AssertionError(e);
 103         }
 104     }
 105 
 106     static String rootNameInCallee;
 107     static String rootNameInCaller;
 108 
 109     @BytecodeParserForceInline
 110     public static void rootNameWithinInstrumentationSnippet() {
 111         GraalDirectives.instrumentationBegin();
 112         rootNameInCallee = GraalDirectives.rootName();
 113         GraalDirectives.instrumentationEnd();
 114     }
 115 
 116     public static void callerSnippet1() {
 117         rootNameWithinInstrumentationSnippet();
 118 
 119         GraalDirectives.instrumentationBegin();
 120         rootNameInCaller = GraalDirectives.rootName();
 121         GraalDirectives.instrumentationEnd();
 122     }
 123 
 124     @SuppressWarnings("try")
 125     private void assertEquals(StructuredGraph graph, InstalledCode code, Object expected, Object actual) {
 126         if (!Objects.equal(expected, actual)) {
 127             Formatter buf = new Formatter();
 128 
 129             try (Scope s = Debug.sandbox("PrintingGraph", null)) {
 130                 Map<Object, Object> properties = new HashMap<>();
 131                 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 132                 IdealGraphPrinter printer = new IdealGraphPrinter(baos, true, getSnippetReflection());
 133                 printer.beginGroup("RootNameDirectiveTest", "RootNameDirectiveTest", graph.method(), -1, null);
 134                 properties.put("graph", graph.toString());
 135                 properties.put("scope", Debug.currentScope());
 136                 printer.print(graph, graph.method().format("%H.%n(%p)"), properties);
 137                 printer.endGroup();
 138                 printer.close();
 139                 buf.format("-- Graph -- %n%s", baos.toString());
 140             } catch (Throwable e) {
 141                 buf.format("%nError printing graph: %s", e);
 142             }
 143             try {
 144                 CodeCacheProvider codeCache = getCodeCache();
 145                 Method disassemble = codeCache.getClass().getMethod("disassemble", InstalledCode.class);
 146                 buf.format("%n-- Code -- %n%s", disassemble.invoke(codeCache, code));
 147             } catch (NoSuchMethodException e) {
 148                 // Not a HotSpotCodeCacheProvider
 149             } catch (Exception e) {
 150                 buf.format("%nError disassembling code: %s", e);
 151             }
 152             Assert.assertEquals(buf.toString(), expected, actual);
 153         }
 154     }
 155 
 156     @SuppressWarnings("try")
 157     @Test
 158     public void testRootNameWithinInstrumentationAtCallee() {
 159         try (OverrideScope s = OptionValue.override(GraalOptions.UseGraalInstrumentation, true)) {
 160             ResolvedJavaMethod method = getResolvedJavaMethod("callerSnippet1");
 161             executeExpected(method, null); // ensure the method is fully resolved
 162             rootNameInCallee = null;
 163             rootNameInCaller = null;
 164             // We expect both rootName1 and rootName2 are set to the name of the target snippet.
 165             StructuredGraph graph = parseForCompile(method);
 166             InstalledCode code = getCode(method, graph);
 167             code.executeVarargs();
 168             assertEquals(graph, code, toString(method), rootNameInCallee);
 169             assertEquals(graph, code, rootNameInCallee, rootNameInCaller);
 170         } catch (Throwable e) {
 171             throw new AssertionError(e);
 172         }
 173     }
 174 
 175 }