1 /*
2  * Copyright (c) 2019, 2020, 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 java.util.ArrayList;
28 import java.util.List;
29 
30 import jdk.internal.vm.compiler.collections.MapCursor;
31 import org.graalvm.compiler.api.test.Graal;
32 import org.graalvm.compiler.core.common.CompilationIdentifier;
33 import org.graalvm.compiler.core.common.GraalOptions;
34 import org.graalvm.compiler.core.target.Backend;
35 import org.graalvm.compiler.core.test.GraalCompilerTest;
36 import org.graalvm.compiler.debug.DebugContext;
37 import org.graalvm.compiler.debug.DebugContext.Builder;
38 import org.graalvm.compiler.nodes.Cancellable;
39 import org.graalvm.compiler.nodes.StructuredGraph;
40 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
41 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
42 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
43 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
44 import org.graalvm.compiler.options.OptionValues;
45 import org.graalvm.compiler.phases.util.Providers;
46 import org.graalvm.compiler.runtime.RuntimeProvider;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.junit.runners.Parameterized;
50 
51 import jdk.vm.ci.meta.MetaAccessProvider;
52 import jdk.vm.ci.meta.ResolvedJavaMethod;
53 import jdk.vm.ci.meta.ResolvedJavaType;
54 
55 /**
56  * Exercise
57  * {@link org.graalvm.compiler.nodes.spi.Replacements#getIntrinsicGraph(ResolvedJavaMethod, CompilationIdentifier, DebugContext, AllowAssumptions, Cancellable)}
58  * with regular method substitutions and encoded graphs.
59  */
60 @RunWith(Parameterized.class)
61 public class RootMethodSubstitutionTest extends GraalCompilerTest {
62 
RootMethodSubstitutionTest(ResolvedJavaMethod method)63     public RootMethodSubstitutionTest(ResolvedJavaMethod method) {
64         this.method = method;
65     }
66 
67     @Parameterized.Parameters(name = "{0}")
data()68     public static List<Object[]> data() {
69         ArrayList<Object[]> ret = new ArrayList<>();
70 
71         Backend backend = Graal.getRequiredCapability(RuntimeProvider.class).getHostBackend();
72         Providers providers = backend.getProviders();
73 
74         MapCursor<String, List<InvocationPlugins.Binding>> cursor = providers.getReplacements().getGraphBuilderPlugins().getInvocationPlugins().getBindings(true).getEntries();
75         MetaAccessProvider metaAccess = providers.getMetaAccess();
76         while (cursor.advance()) {
77             String className = cursor.getKey();
78             ResolvedJavaType type = null;
79             try {
80                 String typeName = className.substring(1, className.length() - 1).replace('/', '.');
81                 ClassLoader cl = ClassLoader.getSystemClassLoader();
82                 Class<?> clazz = Class.forName(typeName, true, cl);
83                 type = metaAccess.lookupJavaType(clazz);
84             } catch (ClassNotFoundException e) {
85                 continue;
86             }
87 
88             for (InvocationPlugins.Binding binding : cursor.getValue()) {
89                 if (binding.plugin instanceof MethodSubstitutionPlugin) {
90                     ResolvedJavaMethod original = null;
91                     for (ResolvedJavaMethod declared : type.getDeclaredMethods()) {
92                         if (declared.getName().equals(binding.name)) {
93                             if (declared.isStatic() == binding.isStatic) {
94                                 if (declared.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
95                                     original = declared;
96                                     break;
97                                 }
98                             }
99                         }
100                     }
101                     if (!original.isNative()) {
102                         // Make sure the plugin we found hasn't been overridden.
103                         InvocationPlugin plugin = providers.getReplacements().getGraphBuilderPlugins().getInvocationPlugins().lookupInvocation(original);
104                         if (plugin instanceof MethodSubstitutionPlugin) {
105                             ret.add(new Object[]{original});
106                         }
107                     }
108                 }
109             }
110         }
111         return ret;
112     }
113 
114     private final ResolvedJavaMethod method;
115 
getIntrinsicGraph(boolean useEncodedGraphs)116     private StructuredGraph getIntrinsicGraph(boolean useEncodedGraphs) {
117         OptionValues options = new OptionValues(getDebugContext().getOptions(), GraalOptions.UseEncodedGraphs, useEncodedGraphs);
118         DebugContext debugContext = new Builder(options, getDebugHandlersFactories()).description(getDebugContext().getDescription()).build();
119         return getReplacements().getIntrinsicGraph(method, CompilationIdentifier.INVALID_COMPILATION_ID, debugContext, AllowAssumptions.YES, null);
120     }
121 
122     StructuredGraph expectedGraph;
123     StructuredGraph actualGraph;
124 
125     @Override
checkHighTierGraph(StructuredGraph graph)126     protected void checkHighTierGraph(StructuredGraph graph) {
127         // Capture the graphs after high tier
128         if (expectedGraph == null) {
129             expectedGraph = (StructuredGraph) graph.copy(graph.getDebug());
130         } else {
131             assert actualGraph == null;
132             actualGraph = (StructuredGraph) graph.copy(graph.getDebug());
133         }
134         super.checkHighTierGraph(graph);
135     }
136 
137     @Test
test()138     public void test() {
139         StructuredGraph regularGraph = getIntrinsicGraph(false);
140         assertTrue(regularGraph != null, "must produce a graph");
141         getCode(method, regularGraph);
142 
143         StructuredGraph encodedGraph = getIntrinsicGraph(true);
144         assertTrue(encodedGraph != null, "must produce a graph");
145         getCode(method, encodedGraph);
146 
147         // Compare the high tier graphs since the final graph might have scheduler
148         // differences because of different usage ordering.
149         assertEquals(expectedGraph, actualGraph, true, false);
150     }
151 
152 }
153