package org.graalvm.compiler.replacements.test;
import static org.graalvm.compiler.core.GraalCompiler.compileGraph;
import static org.graalvm.compiler.core.common.GraalOptions.TrackNodeSourcePosition;
import java.util.List;
import org.graalvm.compiler.api.directives.GraalDirectives;
import org.graalvm.compiler.api.replacements.ClassSubstitution;
import org.graalvm.compiler.api.replacements.MethodSubstitution;
import org.graalvm.compiler.code.CompilationResult;
import org.graalvm.compiler.code.SourceMapping;
import org.graalvm.compiler.graph.Node;
import org.graalvm.compiler.graph.NodeSourcePosition;
import org.graalvm.compiler.lir.asm.CompilationResultBuilderFactory;
import org.graalvm.compiler.nodes.StructuredGraph;
import org.graalvm.compiler.nodes.debug.BlackholeNode;
import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
import org.graalvm.compiler.options.OptionValues;
import org.graalvm.compiler.phases.OptimisticOptimizations;
import org.graalvm.compiler.replacements.classfile.ClassfileBytecodeProvider;
import org.junit.Assert;
import org.junit.Test;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
public class SubstitutionNodeSourcePositionTest extends ReplacementsTest {
private static class TestMethod {
public static int test(int i) {
return i;
}
}
@ClassSubstitution(TestMethod.class)
public static class TestMethodSubstitution {
@MethodSubstitution
public static int test(int i) {
blackhole(i);
return i;
}
@Node.NodeIntrinsic(BlackholeNode.class)
private static native void blackhole(int i);
}
@Override
protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
new PluginFactory_SubstitutionNodeSourcePositionTest().registerPlugins(invocationPlugins, null);
ClassfileBytecodeProvider bytecodeProvider = getSystemClassLoaderBytecodeProvider();
InvocationPlugins.Registration r = new InvocationPlugins.Registration(invocationPlugins, TestMethod.class, bytecodeProvider);
r.registerMethodSubstitution(TestMethodSubstitution.class, "test", int.class);
super.registerInvocationPlugins(invocationPlugins);
}
public int methodSubstitution() {
return TestMethod.test(42);
}
@Test
public void testMethodSubstitution() {
checkMappings("methodSubstitution", true, TestMethod.class, "test");
}
public void snippetLowering(String[] array, String value) {
array[0] = value;
}
@Test
public void testSnippetLowering() {
checkMappings("snippetLowering", true, SubstitutionNodeSourcePositionTest.class, "snippetLowering");
}
public int methodPlugin(int i) {
GraalDirectives.blackhole(i);
return i;
}
@Test
public void testMethodPlugin() {
checkMappings("methodPlugin", false, GraalDirectives.class, "blackhole");
}
private void checkMappings(String snippetMethod, boolean hasBytecodes, Class<?> boundaryClass, String boundaryMethod) {
List<SourceMapping> mappings = getSourceMappings(snippetMethod);
ResolvedJavaType resolvedJavaType = getMetaAccess().lookupJavaType(boundaryClass);
boolean found = false;
Assert.assertTrue("must have mappings", !mappings.isEmpty());
for (SourceMapping mapping : mappings) {
NodeSourcePosition callee = null;
for (NodeSourcePosition pos = mapping.getSourcePosition(); pos != null; pos = pos.getCaller()) {
ResolvedJavaMethod method = pos.getMethod();
if (method.getName().equals(boundaryMethod) && method.getDeclaringClass().equals(resolvedJavaType)) {
if ((callee != null) == hasBytecodes) {
if (hasBytecodes) {
assertTrue(callee.isSubstitution());
}
assertTrue(pos.trim() == pos);
assertTrue(mapping.getSourcePosition().trim() == pos);
found = true;
}
}
callee = pos;
}
}
Assert.assertTrue("must have substitution for " + resolvedJavaType + "." + boundaryMethod, found);
}
private List<SourceMapping> getSourceMappings(String name) {
final ResolvedJavaMethod method = getResolvedJavaMethod(name);
final OptionValues options = new OptionValues(getInitialOptions(), TrackNodeSourcePosition, true);
final StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES, options);
final CompilationResult cr = compileGraph(graph, graph.method(), getProviders(), getBackend(), getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, graph.getProfilingInfo(),
createSuites(graph.getOptions()), createLIRSuites(graph.getOptions()), new CompilationResult(graph.compilationId()), CompilationResultBuilderFactory.Default, true);
return cr.getSourceMappings();
}
}