1 /*
2  * Copyright (c) 2013, 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.hotspot;
26 
27 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
28 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
29 import static org.graalvm.compiler.core.common.GraalOptions.UseEncodedGraphs;
30 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
31 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.ROOT_COMPILATION;
32 
33 import java.util.Set;
34 
35 import jdk.internal.vm.compiler.collections.EconomicSet;
36 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
37 import org.graalvm.compiler.bytecode.BytecodeProvider;
38 import org.graalvm.compiler.core.common.CompilationIdentifier;
39 import org.graalvm.compiler.debug.DebugContext;
40 import org.graalvm.compiler.debug.GraalError;
41 import org.graalvm.compiler.graph.NodeSourcePosition;
42 import org.graalvm.compiler.hotspot.meta.HotSpotWordOperationPlugin;
43 import org.graalvm.compiler.hotspot.word.HotSpotOperation;
44 import org.graalvm.compiler.nodes.Invoke;
45 import org.graalvm.compiler.nodes.StructuredGraph;
46 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
47 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderPlugin;
48 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
49 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
50 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
51 import org.graalvm.compiler.options.OptionValues;
52 import org.graalvm.compiler.phases.util.Providers;
53 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
54 import org.graalvm.compiler.replacements.ReplacementsImpl;
55 
56 import jdk.vm.ci.code.TargetDescription;
57 import jdk.vm.ci.common.NativeImageReinitialize;
58 import jdk.vm.ci.meta.ResolvedJavaMethod;
59 
60 /**
61  * Filters certain method substitutions based on whether there is underlying hardware support for
62  * them.
63  */
64 public class HotSpotReplacementsImpl extends ReplacementsImpl {
HotSpotReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target)65     public HotSpotReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target) {
66         super(new GraalDebugHandlersFactory(snippetReflection), providers, snippetReflection, bytecodeProvider, target);
67     }
68 
HotSpotReplacementsImpl(HotSpotReplacementsImpl replacements, Providers providers)69     HotSpotReplacementsImpl(HotSpotReplacementsImpl replacements, Providers providers) {
70         super(new GraalDebugHandlersFactory(replacements.snippetReflection), providers, replacements.snippetReflection,
71                         replacements.getDefaultReplacementBytecodeProvider(), replacements.target);
72     }
73 
74     @Override
getIntrinsifyingPlugin(ResolvedJavaMethod method)75     public Class<? extends GraphBuilderPlugin> getIntrinsifyingPlugin(ResolvedJavaMethod method) {
76         return method.getAnnotation(HotSpotOperation.class) != null ? HotSpotWordOperationPlugin.class : super.getIntrinsifyingPlugin(method);
77     }
78 
79     @Override
registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options)80     public void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options) {
81         if (!IS_IN_NATIVE_IMAGE) {
82             if (IS_BUILDING_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) {
83                 synchronized (HotSpotReplacementsImpl.class) {
84                     if (snippetEncoder == null) {
85                         snippetEncoder = new SymbolicSnippetEncoder(this);
86                     }
87                     snippetEncoder.registerMethodSubstitution(plugin, original, context, options);
88                 }
89             }
90         }
91     }
92 
93     @Override
getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug)94     public StructuredGraph getIntrinsicGraph(ResolvedJavaMethod method, CompilationIdentifier compilationId, DebugContext debug) {
95         boolean useEncodedGraphs = UseEncodedGraphs.getValue(debug.getOptions());
96         if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
97             HotSpotReplacementsImpl replacements = (HotSpotReplacementsImpl) providers.getReplacements();
98             InvocationPlugin plugin = replacements.getGraphBuilderPlugins().getInvocationPlugins().lookupInvocation(method);
99             if (plugin instanceof MethodSubstitutionPlugin) {
100                 MethodSubstitutionPlugin msp = (MethodSubstitutionPlugin) plugin;
101                 if (useEncodedGraphs) {
102                     replacements.registerMethodSubstitution(msp, method, ROOT_COMPILATION, debug.getOptions());
103                 }
104                 StructuredGraph methodSubstitution = replacements.getMethodSubstitution(msp, method, ROOT_COMPILATION, StructuredGraph.AllowAssumptions.YES, debug.getOptions());
105                 methodSubstitution.resetDebug(debug);
106                 return methodSubstitution;
107             }
108             return null;
109         }
110         return super.getIntrinsicGraph(method, compilationId, debug);
111     }
112 
113     @Override
getSubstitution(ResolvedJavaMethod targetMethod, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition, OptionValues options)114     public StructuredGraph getSubstitution(ResolvedJavaMethod targetMethod, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition, OptionValues options) {
115         boolean useEncodedGraphs = UseEncodedGraphs.getValue(options);
116         if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
117             InvocationPlugin plugin = getGraphBuilderPlugins().getInvocationPlugins().lookupInvocation(targetMethod);
118             if (plugin instanceof MethodSubstitutionPlugin && (!plugin.inlineOnly() || invokeBci >= 0)) {
119                 MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
120                 if (!IS_IN_NATIVE_IMAGE && useEncodedGraphs) {
121                     registerMethodSubstitution(msPlugin, targetMethod, INLINE_AFTER_PARSING, options);
122                 }
123                 // This assumes the normal path creates the graph using
124                 // GraphBuilderConfiguration.getSnippetDefault with omits exception edges
125                 StructuredGraph subst = getMethodSubstitution(msPlugin, targetMethod, INLINE_AFTER_PARSING, StructuredGraph.AllowAssumptions.NO, options);
126                 return subst;
127             }
128         }
129 
130         return super.getSubstitution(targetMethod, invokeBci, trackNodeSourcePosition, replaceePosition, options);
131     }
132 
133     @Override
notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke)134     public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
135         if (b.parsingIntrinsic() && snippetEncoder != null) {
136             if (getIntrinsifyingPlugin(method) != null) {
137                 snippetEncoder.addDelayedInvocationPluginMethod(method);
138                 return;
139             }
140         }
141         super.notifyNotInlined(b, method, invoke);
142     }
143 
144     // When assertions are enabled, these fields are used to ensure all snippets are
145     // registered during Graal initialization which in turn ensures that native image
146     // building will not miss any snippets.
147     @NativeImageReinitialize private EconomicSet<ResolvedJavaMethod> registeredSnippets = EconomicSet.create();
148     private boolean snippetRegistrationClosed;
149 
150     @Override
registerSnippet(ResolvedJavaMethod method, ResolvedJavaMethod original, Object receiver, boolean trackNodeSourcePosition, OptionValues options)151     public void registerSnippet(ResolvedJavaMethod method, ResolvedJavaMethod original, Object receiver, boolean trackNodeSourcePosition, OptionValues options) {
152         if (!IS_IN_NATIVE_IMAGE) {
153             assert !snippetRegistrationClosed : "Cannot register snippet after registration is closed: " + method.format("%H.%n(%p)");
154             assert registeredSnippets.add(method) : "Cannot register snippet twice: " + method.format("%H.%n(%p)");
155             if (IS_BUILDING_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) {
156                 synchronized (HotSpotReplacementsImpl.class) {
157                     if (snippetEncoder == null) {
158                         snippetEncoder = new SymbolicSnippetEncoder(this);
159                     }
160                     snippetEncoder.registerSnippet(method, original, receiver, trackNodeSourcePosition, options);
161                 }
162             }
163         }
164     }
165 
166     @Override
closeSnippetRegistration()167     public void closeSnippetRegistration() {
168         snippetRegistrationClosed = true;
169     }
170 
getEncodedSnippets()171     private static SymbolicSnippetEncoder.EncodedSnippets getEncodedSnippets() {
172         return encodedSnippets;
173     }
174 
getSnippetMethods()175     public Set<ResolvedJavaMethod> getSnippetMethods() {
176         if (snippetEncoder != null) {
177             return snippetEncoder.getSnippetMethods();
178         }
179         return null;
180     }
181 
setEncodedSnippets(SymbolicSnippetEncoder.EncodedSnippets encodedSnippets)182     static void setEncodedSnippets(SymbolicSnippetEncoder.EncodedSnippets encodedSnippets) {
183         HotSpotReplacementsImpl.encodedSnippets = encodedSnippets;
184     }
185 
encode(OptionValues options)186     public boolean encode(OptionValues options) {
187         SymbolicSnippetEncoder encoder = HotSpotReplacementsImpl.snippetEncoder;
188         if (encoder != null) {
189             return encoder.encode(options);
190         }
191         return false;
192     }
193 
194     private static volatile SymbolicSnippetEncoder.EncodedSnippets encodedSnippets;
195 
196     @NativeImageReinitialize private static SymbolicSnippetEncoder snippetEncoder;
197 
198     @Override
getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition, OptionValues options)199     public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition,
200                     OptionValues options) {
201         StructuredGraph graph = getEncodedSnippet(method, args, StructuredGraph.AllowAssumptions.NO, options);
202         if (graph != null) {
203             return graph;
204         }
205 
206         assert !IS_IN_NATIVE_IMAGE : "should be using encoded snippets";
207         return super.getSnippet(method, recursiveEntry, args, trackNodeSourcePosition, replaceePosition, options);
208     }
209 
getEncodedSnippet(ResolvedJavaMethod method, Object[] args, StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options)210     private StructuredGraph getEncodedSnippet(ResolvedJavaMethod method, Object[] args, StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
211         boolean useEncodedGraphs = UseEncodedGraphs.getValue(options);
212         if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
213             synchronized (HotSpotReplacementsImpl.class) {
214                 if (!IS_IN_NATIVE_IMAGE) {
215                     snippetEncoder.encode(options);
216                 }
217 
218                 if (getEncodedSnippets() == null) {
219                     throw GraalError.shouldNotReachHere("encoded snippets not found");
220                 }
221                 StructuredGraph graph = getEncodedSnippets().getEncodedSnippet(method, this, args, allowAssumptions, options);
222                 if (graph == null) {
223                     throw GraalError.shouldNotReachHere("snippet not found: " + method.format("%H.%n(%p)"));
224                 }
225                 return graph;
226             }
227         } else {
228             assert registeredSnippets == null || registeredSnippets.contains(method) : "Asking for snippet method that was never registered: " + method.format("%H.%n(%p)");
229         }
230         return null;
231     }
232 
233     @Override
getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options)234     public StructuredGraph getMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context,
235                     StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) {
236         boolean useEncodedGraphs = UseEncodedGraphs.getValue(options);
237         if (IS_IN_NATIVE_IMAGE || useEncodedGraphs) {
238             if (!IS_IN_NATIVE_IMAGE) {
239                 snippetEncoder.encode(options);
240             }
241 
242             if (getEncodedSnippets() == null) {
243                 throw GraalError.shouldNotReachHere("encoded snippets not found");
244             }
245             return getEncodedSnippets().getMethodSubstitutionGraph(plugin, original, this, context, allowAssumptions, options);
246         }
247         return null;
248     }
249 
250 }
251