1 /* 2 * Copyright (c) 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.replacements.test; 26 27 import static org.graalvm.compiler.core.GraalCompiler.compileGraph; 28 import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition; 29 import static org.graalvm.compiler.core.common.GraalOptions.UseEncodedGraphs; 30 31 import java.util.List; 32 33 import org.graalvm.compiler.api.directives.GraalDirectives; 34 import org.graalvm.compiler.api.replacements.ClassSubstitution; 35 import org.graalvm.compiler.api.replacements.MethodSubstitution; 36 import org.graalvm.compiler.code.CompilationResult; 37 import org.graalvm.compiler.code.SourceMapping; 38 import org.graalvm.compiler.graph.Node; 39 import org.graalvm.compiler.graph.NodeSourcePosition; 40 import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory; 41 import org.graalvm.compiler.nodes.StructuredGraph; 42 import org.graalvm.compiler.nodes.debug.BlackholeNode; 43 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; 44 import org.graalvm.compiler.options.OptionValues; 45 import org.graalvm.compiler.phases.OptimisticOptimizations; 46 import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider; 47 import org.junit.Assert; 48 import org.junit.Assume; 49 import org.junit.Test; 50 51 import jdk.vm.ci.meta.ResolvedJavaMethod; 52 import jdk.vm.ci.meta.ResolvedJavaType; 53 54 /** 55 * Test that various substitution implementations produce the expected 56 * {@link org.graalvm.compiler.graph.NodeSourcePosition} structure. Method substitutions and method 57 * plugins should leave behind a frame for the substitution. Method substitutions should have 58 * bytecodes below the substitution. Snippet lowerings should just have the bytecodes without a 59 * marker frame. 60 */ 61 public class SubstitutionNodeSourcePositionTest extends ReplacementsTest { 62 63 private static class TestMethod { 64 65 public static int test(int i) { 66 return i; 67 } 68 } 69 70 @ClassSubstitution(TestMethod.class) 71 public static class TestMethodSubstitution { 72 73 @MethodSubstitution 74 public static int test(int i) { 75 blackhole(i); 76 return i; 77 } 78 79 @Node.NodeIntrinsic(BlackholeNode.class) 80 private static native void blackhole(int i); 81 } 82 83 @Override 84 protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) { 85 new PluginFactory_SubstitutionNodeSourcePositionTest().registerPlugins(invocationPlugins, null); 86 ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider(); 87 InvocationPlugins.Registration r = new InvocationPlugins.Registration(invocationPlugins, TestMethod.class, bytecodeProvider); 88 r.registerMethodSubstitution(TestMethodSubstitution.class, "test", int.class); 89 super.registerInvocationPlugins(invocationPlugins); 90 } 91 92 public int methodSubstitution() { 93 return TestMethod.test(42); 94 } 95 96 @Test 97 public void testMethodSubstitution() { 98 // @formatter:off 99 // Expect mappings of the form: 100 // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest$TestMethodSubstitution.blackhole(int) [bci: -1] 101 // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest$TestMethodSubstitution.test(SubstitutionNodeSourcePositionTest.java:71) [bci: 1] Substitution 102 // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest$TestMethod.test(int) [bci: -1] 103 // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest.methodSubstitution(SubstitutionNodeSourcePositionTest.java:89) [bci: 2] 104 // @formatter:on 105 Assume.assumeFalse(UseEncodedGraphs.getValue(getInitialOptions())); 106 checkMappings("methodSubstitution", true, TestMethod.class, "test"); 107 } 108 109 public void snippetLowering(String[] array, String value) { 110 array[0] = value; 111 } 112 113 @Test 114 public void testSnippetLowering() { 115 // @formatter:off 116 // Expect mappings of the form: 117 // at org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.serialWriteBarrier(WriteBarrierSnippets.java:140) [bci: 18] 118 // at org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.serialPreciseWriteBarrier(WriteBarrierSnippets.java:158) [bci: 5] Substitution 119 // at org.graalvm.compiler.hotspot.replacements.WriteBarrierSnippets.serialPreciseWriteBarrier(AddressNode$Address, WriteBarrierSnippets$Counters) [bci: -1] Substitution 120 // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest.snippetLowering(SubstitutionNodeSourcePositionTest.java:99) [bci: 3] 121 // @formatter:on 122 // 123 // The precise snippet bytecodes don't matter, just ensure that some actually appear after 124 // lowering. 125 Assume.assumeFalse(UseEncodedGraphs.getValue(getInitialOptions())); 126 checkMappings("snippetLowering", true, SubstitutionNodeSourcePositionTest.class, "snippetLowering"); 127 } 128 129 public int methodPlugin(int i) { 130 GraalDirectives.blackhole(i); 131 return i; 132 } 133 134 @Test 135 public void testMethodPlugin() { 136 // @formatter:off 137 // Expect mappings of the form: 138 // at org.graalvm.compiler.api.directives.GraalDirectives.blackhole(int) [bci: -1] 139 // at org.graalvm.compiler.replacements.test.SubstitutionNodeSourcePositionTest.methodPlugin(SubstitutionNodeSourcePositionTest.java:109) [bci: 1] 140 // @formatter:on 141 checkMappings("methodPlugin", false, GraalDirectives.class, "blackhole"); 142 } 143 144 private void checkMappings(String snippetMethod, boolean hasBytecodes, Class<?> boundaryClass, String boundaryMethod) { 145 List<SourceMapping> mappings = getSourceMappings(snippetMethod); 146 ResolvedJavaType resolvedJavaType = getMetaAccess().lookupJavaType(boundaryClass); 147 boolean found = false; 148 Assert.assertTrue("must have mappings", !mappings.isEmpty()); 149 for (SourceMapping mapping : mappings) { 150 NodeSourcePosition callee = null; 151 for (NodeSourcePosition pos = mapping.getSourcePosition(); pos != null; pos = pos.getCaller()) { 152 ResolvedJavaMethod method = pos.getMethod(); 153 if (method.getName().equals(boundaryMethod) && method.getDeclaringClass().equals(resolvedJavaType)) { 154 if ((callee != null) == hasBytecodes) { 155 if (hasBytecodes) { 156 assertTrue(callee.isSubstitution()); 157 } 158 assertTrue(pos.trim() == pos); 159 assertTrue(mapping.getSourcePosition().trim() == pos); 160 found = true; 161 } 162 } 163 callee = pos; 164 } 165 } 166 Assert.assertTrue("must have substitution for " + resolvedJavaType + "." + boundaryMethod, found); 167 } 168 169 private List<SourceMapping> getSourceMappings(String name) { 170 final ResolvedJavaMethod method = getResolvedJavaMethod(name); 171 final OptionValues options = new OptionValues(getInitialOptions(), TrackNodeSourcePosition, true); 172 final StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES, options); 173 final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(), 174 createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default, true); 175 return cr.getSourceMappings(); 176 } 177 }