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