1 /*
2  * Copyright (c) 2011, 2016, 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;
26 
27 import static org.graalvm.compiler.core.common.GraalOptions.UseSnippetGraphCache;
28 import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM;
29 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineDuringParsing;
30 import static org.graalvm.compiler.java.BytecodeParserOptions.InlineIntrinsicsDuringParsing;
31 import static org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo.createIntrinsicInlineInfo;
32 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
33 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
34 
35 import java.util.Collections;
36 import java.util.List;
37 import java.util.concurrent.ConcurrentHashMap;
38 import java.util.concurrent.ConcurrentMap;
39 import java.util.concurrent.atomic.AtomicInteger;
40 
41 import jdk.internal.vm.compiler.collections.EconomicMap;
42 import jdk.internal.vm.compiler.collections.Equivalence;
43 import org.graalvm.compiler.api.replacements.Fold;
44 import org.graalvm.compiler.api.replacements.MethodSubstitution;
45 import org.graalvm.compiler.api.replacements.Snippet;
46 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
47 import org.graalvm.compiler.api.replacements.SnippetTemplateCache;
48 import org.graalvm.compiler.bytecode.Bytecode;
49 import org.graalvm.compiler.bytecode.BytecodeProvider;
50 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
51 import org.graalvm.compiler.core.common.GraalOptions;
52 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
53 import org.graalvm.compiler.debug.DebugCloseable;
54 import org.graalvm.compiler.debug.DebugContext;
55 import org.graalvm.compiler.debug.DebugContext.Description;
56 import org.graalvm.compiler.debug.DebugHandlersFactory;
57 import org.graalvm.compiler.debug.GraalError;
58 import org.graalvm.compiler.debug.TimerKey;
59 import org.graalvm.compiler.graph.Node;
60 import org.graalvm.compiler.graph.NodeSourcePosition;
61 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
62 import org.graalvm.compiler.java.GraphBuilderPhase;
63 import org.graalvm.compiler.java.GraphBuilderPhase.Instance;
64 import org.graalvm.compiler.nodes.CallTargetNode;
65 import org.graalvm.compiler.nodes.Invoke;
66 import org.graalvm.compiler.nodes.StateSplit;
67 import org.graalvm.compiler.nodes.StructuredGraph;
68 import org.graalvm.compiler.nodes.ValueNode;
69 import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin;
70 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration;
71 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
72 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
73 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
74 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
75 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
76 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
77 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
78 import org.graalvm.compiler.nodes.spi.Replacements;
79 import org.graalvm.compiler.nodes.spi.StampProvider;
80 import org.graalvm.compiler.options.OptionValues;
81 import org.graalvm.compiler.phases.OptimisticOptimizations;
82 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
83 import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
84 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
85 import org.graalvm.compiler.phases.tiers.PhaseContext;
86 import org.graalvm.compiler.phases.util.Providers;
87 import org.graalvm.compiler.word.Word;
88 import org.graalvm.compiler.word.WordOperationPlugin;
89 
90 import jdk.vm.ci.code.TargetDescription;
91 import jdk.vm.ci.meta.ConstantReflectionProvider;
92 import jdk.vm.ci.meta.MetaAccessProvider;
93 import jdk.vm.ci.meta.ResolvedJavaMethod;
94 import jdk.vm.ci.meta.ResolvedJavaType;
95 
96 public class ReplacementsImpl implements Replacements, InlineInvokePlugin {
97 
98     protected final OptionValues options;
99     public final Providers providers;
100     public final SnippetReflectionProvider snippetReflection;
101     public final TargetDescription target;
102     private GraphBuilderConfiguration.Plugins graphBuilderPlugins;
103     private final DebugHandlersFactory debugHandlersFactory;
104 
105     @Override
getOptions()106     public OptionValues getOptions() {
107         return options;
108     }
109 
110     /**
111      * The preprocessed replacement graphs.
112      */
113     protected final ConcurrentMap<ResolvedJavaMethod, StructuredGraph> graphs;
114 
115     /**
116      * The default {@link BytecodeProvider} to use for accessing the bytecode of a replacement if
117      * the replacement doesn't provide another {@link BytecodeProvider}.
118      */
119     protected final BytecodeProvider defaultBytecodeProvider;
120 
setGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins)121     public void setGraphBuilderPlugins(GraphBuilderConfiguration.Plugins plugins) {
122         assert this.graphBuilderPlugins == null;
123         this.graphBuilderPlugins = plugins;
124     }
125 
126     @Override
getGraphBuilderPlugins()127     public GraphBuilderConfiguration.Plugins getGraphBuilderPlugins() {
128         return graphBuilderPlugins;
129     }
130 
hasGeneratedInvocationPluginAnnotation(ResolvedJavaMethod method)131     protected boolean hasGeneratedInvocationPluginAnnotation(ResolvedJavaMethod method) {
132         return method.getAnnotation(Node.NodeIntrinsic.class) != null || method.getAnnotation(Fold.class) != null;
133     }
134 
hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method)135     protected boolean hasGenericInvocationPluginAnnotation(ResolvedJavaMethod method) {
136         return method.getAnnotation(Word.Operation.class) != null;
137     }
138 
139     private static final int MAX_GRAPH_INLINING_DEPTH = 100; // more than enough
140 
141     /**
142      * Determines whether a given method should be inlined based on whether it has a substitution or
143      * whether the inlining context is already within a substitution.
144      *
145      * @return an object specifying how {@code method} is to be inlined or null if it should not be
146      *         inlined based on substitution related criteria
147      */
148     @Override
shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args)149     public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
150         Bytecode subst = getSubstitutionBytecode(method);
151         if (subst != null) {
152             if (b.parsingIntrinsic() || InlineDuringParsing.getValue(b.getOptions()) || InlineIntrinsicsDuringParsing.getValue(b.getOptions())) {
153                 // Forced inlining of intrinsics
154                 return createIntrinsicInlineInfo(subst.getMethod(), method, subst.getOrigin());
155             }
156             return null;
157         }
158         if (b.parsingIntrinsic()) {
159             assert b.getDepth() < MAX_GRAPH_INLINING_DEPTH : "inlining limit exceeded";
160 
161             // Force inlining when parsing replacements
162             return createIntrinsicInlineInfo(method, null, defaultBytecodeProvider);
163         } else {
164             assert method.getAnnotation(NodeIntrinsic.class) == null : String.format("@%s method %s must only be called from within a replacement%n%s", NodeIntrinsic.class.getSimpleName(),
165                             method.format("%h.%n"), b);
166         }
167         return null;
168     }
169 
170     @Override
171     public void notifyNotInlined(GraphBuilderContext b, ResolvedJavaMethod method, Invoke invoke) {
172         if (b.parsingIntrinsic()) {
173             IntrinsicContext intrinsic = b.getIntrinsic();
174             if (!intrinsic.isCallToOriginal(method)) {
175                 if (hasGeneratedInvocationPluginAnnotation(method)) {
176                     throw new GraalError("%s should have been handled by a %s", method.format("%H.%n(%p)"), GeneratedInvocationPlugin.class.getSimpleName());
177                 }
178                 if (hasGenericInvocationPluginAnnotation(method)) {
179                     throw new GraalError("%s should have been handled by %s", method.format("%H.%n(%p)"), WordOperationPlugin.class.getSimpleName());
180                 }
181 
182                 throw new GraalError("All non-recursive calls in the intrinsic %s must be inlined or intrinsified: found call to %s",
183                                 intrinsic.getIntrinsicMethod().format("%H.%n(%p)"), method.format("%h.%n(%p)"));
184             }
185         }
186     }
187 
188     // This map is key'ed by a class name instead of a Class object so that
189     // it is stable across VM executions (in support of replay compilation).
190     private final EconomicMap<String, SnippetTemplateCache> snippetTemplateCache;
191 
192     public ReplacementsImpl(OptionValues options, DebugHandlersFactory debugHandlersFactory, Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider,
193                     TargetDescription target) {
194         this.options = options;
195         this.providers = providers.copyWith(this);
196         this.snippetReflection = snippetReflection;
197         this.target = target;
198         this.graphs = new ConcurrentHashMap<>();
199         this.snippetTemplateCache = EconomicMap.create(Equivalence.DEFAULT);
200         this.defaultBytecodeProvider = bytecodeProvider;
201         this.debugHandlersFactory = debugHandlersFactory;
202 
203     }
204 
205     private static final TimerKey SnippetPreparationTime = DebugContext.timer("SnippetPreparationTime");
206 
207     @Override
208     public StructuredGraph getSnippet(ResolvedJavaMethod method, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
209         return getSnippet(method, null, args, trackNodeSourcePosition, replaceePosition);
210     }
211 
212     private static final AtomicInteger nextDebugContextId = new AtomicInteger();
213 
214     protected DebugContext openDebugContext(String idPrefix, ResolvedJavaMethod method) {
215         DebugContext outer = DebugContext.forCurrentThread();
216         Description description = new Description(method, idPrefix + nextDebugContextId.incrementAndGet());
217         List<DebugHandlersFactory> factories = debugHandlersFactory == null ? Collections.emptyList() : Collections.singletonList(debugHandlersFactory);
218         return DebugContext.create(options, description, outer.getGlobalMetrics(), DEFAULT_LOG_STREAM, factories);
219     }
220 
221     @Override
222     @SuppressWarnings("try")
223     public StructuredGraph getSnippet(ResolvedJavaMethod method, ResolvedJavaMethod recursiveEntry, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
224         assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName();
225         assert method.hasBytecodes() : "Snippet must not be abstract or native";
226 
227         StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(method) : null;
228         if (graph == null || (trackNodeSourcePosition && !graph.trackNodeSourcePosition())) {
229             try (DebugContext debug = openDebugContext("Snippet_", method);
230                             DebugCloseable a = SnippetPreparationTime.start(debug)) {
231                 StructuredGraph newGraph = makeGraph(debug, defaultBytecodeProvider, method, args, recursiveEntry, trackNodeSourcePosition, replaceePosition);
232                 DebugContext.counter("SnippetNodeCount[%#s]", method).add(newGraph.getDebug(), newGraph.getNodeCount());
233                 if (!UseSnippetGraphCache.getValue(options) || args != null) {
234                     return newGraph;
235                 }
236                 newGraph.freeze();
237                 if (graph != null) {
238                     graphs.replace(method, graph, newGraph);
239                 } else {
240                     graphs.putIfAbsent(method, newGraph);
241                 }
242                 graph = graphs.get(method);
243             }
244         }
245         assert !trackNodeSourcePosition || graph.trackNodeSourcePosition();
246         return graph;
247     }
248 
249     @Override
250     public void registerSnippet(ResolvedJavaMethod method, boolean trackNodeSourcePosition) {
251         // No initialization needed as snippet graphs are created on demand in getSnippet
252     }
253 
254     @Override
255     public boolean hasSubstitution(ResolvedJavaMethod method, int invokeBci) {
256         InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
257         return plugin != null && (!plugin.inlineOnly() || invokeBci >= 0);
258     }
259 
260     @Override
getDefaultReplacementBytecodeProvider()261     public BytecodeProvider getDefaultReplacementBytecodeProvider() {
262         return defaultBytecodeProvider;
263     }
264 
265     @Override
getSubstitutionBytecode(ResolvedJavaMethod method)266     public Bytecode getSubstitutionBytecode(ResolvedJavaMethod method) {
267         InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
268         if (plugin instanceof MethodSubstitutionPlugin) {
269             MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
270             ResolvedJavaMethod substitute = msPlugin.getSubstitute(providers.getMetaAccess());
271             return msPlugin.getBytecodeProvider().getBytecode(substitute);
272         }
273         return null;
274     }
275 
276     @Override
getSubstitution(ResolvedJavaMethod method, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition)277     public StructuredGraph getSubstitution(ResolvedJavaMethod method, int invokeBci, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
278         StructuredGraph result;
279         InvocationPlugin plugin = graphBuilderPlugins.getInvocationPlugins().lookupInvocation(method);
280         if (plugin != null && (!plugin.inlineOnly() || invokeBci >= 0)) {
281             MetaAccessProvider metaAccess = providers.getMetaAccess();
282             if (plugin instanceof MethodSubstitutionPlugin) {
283                 MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
284                 ResolvedJavaMethod substitute = msPlugin.getSubstitute(metaAccess);
285                 StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(substitute) : null;
286                 if (graph == null || graph.trackNodeSourcePosition() != trackNodeSourcePosition) {
287                     try (DebugContext debug = openDebugContext("Substitution_", method)) {
288                         graph = makeGraph(debug, msPlugin.getBytecodeProvider(), substitute, null, method, trackNodeSourcePosition, replaceePosition);
289                         if (!UseSnippetGraphCache.getValue(options)) {
290                             return graph;
291                         }
292                         graph.freeze();
293                         graphs.putIfAbsent(substitute, graph);
294                         graph = graphs.get(substitute);
295                     }
296                 }
297                 assert graph.isFrozen();
298                 result = graph;
299             } else {
300                 Bytecode code = new ResolvedJavaMethodBytecode(method);
301                 ConstantReflectionProvider constantReflection = providers.getConstantReflection();
302                 ConstantFieldProvider constantFieldProvider = providers.getConstantFieldProvider();
303                 StampProvider stampProvider = providers.getStampProvider();
304                 try (DebugContext debug = openDebugContext("Substitution_", method)) {
305                     result = new IntrinsicGraphBuilder(options, debug, metaAccess, constantReflection, constantFieldProvider, stampProvider, code, invokeBci).buildGraph(plugin);
306                 }
307             }
308         } else {
309             result = null;
310         }
311         return result;
312     }
313 
314     /**
315      * Creates a preprocessed graph for a snippet or method substitution.
316      *
317      * @param bytecodeProvider how to access the bytecode of {@code method}
318      * @param method the snippet or method substitution for which a graph will be created
319      * @param args
320      * @param original the original method if {@code method} is a {@linkplain MethodSubstitution
321      *            substitution} otherwise null
322      * @param trackNodeSourcePosition
323      */
makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition)324     public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, ResolvedJavaMethod method, Object[] args, ResolvedJavaMethod original, boolean trackNodeSourcePosition,
325                     NodeSourcePosition replaceePosition) {
326         return createGraphMaker(method, original).makeGraph(debug, bytecodeProvider, args, trackNodeSourcePosition, replaceePosition);
327     }
328 
329     /**
330      * Can be overridden to return an object that specializes various parts of graph preprocessing.
331      */
createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original)332     protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) {
333         return new GraphMaker(this, substitute, original);
334     }
335 
336     /**
337      * Creates and preprocesses a graph for a replacement.
338      */
339     public static class GraphMaker {
340 
341         /** The replacements object that the graphs are created for. */
342         protected final ReplacementsImpl replacements;
343 
344         /**
345          * The method for which a graph is being created.
346          */
347         protected final ResolvedJavaMethod method;
348 
349         /**
350          * The original method which {@link #method} is substituting. Calls to {@link #method} or
351          * {@link #substitutedMethod} will be replaced with a forced inline of
352          * {@link #substitutedMethod}.
353          */
354         protected final ResolvedJavaMethod substitutedMethod;
355 
GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod)356         protected GraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) {
357             this.replacements = replacements;
358             this.method = substitute;
359             this.substitutedMethod = substitutedMethod;
360         }
361 
362         @SuppressWarnings("try")
makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition)363         public StructuredGraph makeGraph(DebugContext debug, BytecodeProvider bytecodeProvider, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition) {
364             try (DebugContext.Scope s = debug.scope("BuildSnippetGraph", method)) {
365                 assert method.hasBytecodes() : method;
366                 StructuredGraph graph = buildInitialGraph(debug, bytecodeProvider, method, args, trackNodeSourcePosition, replaceePosition);
367 
368                 finalizeGraph(graph);
369 
370                 debug.dump(DebugContext.INFO_LEVEL, graph, "%s: Final", method.getName());
371 
372                 return graph;
373             } catch (Throwable e) {
374                 throw debug.handle(e);
375             }
376         }
377 
378         /**
379          * Does final processing of a snippet graph.
380          */
finalizeGraph(StructuredGraph graph)381         protected void finalizeGraph(StructuredGraph graph) {
382             if (!GraalOptions.SnippetCounters.getValue(replacements.options) || graph.getNodes().filter(SnippetCounterNode.class).isEmpty()) {
383                 int sideEffectCount = 0;
384                 assert (sideEffectCount = graph.getNodes().filter(e -> hasSideEffect(e)).count()) >= 0;
385                 new ConvertDeoptimizeToGuardPhase().apply(graph, null);
386                 assert sideEffectCount == graph.getNodes().filter(e -> hasSideEffect(e)).count() : "deleted side effecting node";
387 
388                 new DeadCodeEliminationPhase(Required).apply(graph);
389             } else {
390                 // ConvertDeoptimizeToGuardPhase will eliminate snippet counters on paths
391                 // that terminate in a deopt so we disable it if the graph contains
392                 // snippet counters. The trade off is that we miss out on guard
393                 // coalescing opportunities.
394             }
395         }
396 
397         /**
398          * Filter nodes which have side effects and shouldn't be deleted from snippets when
399          * converting deoptimizations to guards. Currently this only allows exception constructors
400          * to be eliminated to cover the case when Java assertions are in the inlined code.
401          *
402          * @param node
403          * @return true for nodes that have side effects and are unsafe to delete
404          */
hasSideEffect(Node node)405         private boolean hasSideEffect(Node node) {
406             if (node instanceof StateSplit) {
407                 if (((StateSplit) node).hasSideEffect()) {
408                     if (node instanceof Invoke) {
409                         CallTargetNode callTarget = ((Invoke) node).callTarget();
410                         if (callTarget instanceof MethodCallTargetNode) {
411                             ResolvedJavaMethod targetMethod = ((MethodCallTargetNode) callTarget).targetMethod();
412                             if (targetMethod.isConstructor()) {
413                                 ResolvedJavaType throwableType = replacements.providers.getMetaAccess().lookupJavaType(Throwable.class);
414                                 return !throwableType.isAssignableFrom(targetMethod.getDeclaringClass());
415                             }
416                         }
417                     }
418                     // Not an exception constructor call
419                     return true;
420                 }
421             }
422             // Not a StateSplit
423             return false;
424         }
425 
426         /**
427          * Builds the initial graph for a replacement.
428          */
429         @SuppressWarnings("try")
buildInitialGraph(DebugContext debug, BytecodeProvider bytecodeProvider, final ResolvedJavaMethod methodToParse, Object[] args, boolean trackNodeSourcePosition, NodeSourcePosition replaceePosition)430         protected StructuredGraph buildInitialGraph(DebugContext debug, BytecodeProvider bytecodeProvider, final ResolvedJavaMethod methodToParse, Object[] args, boolean trackNodeSourcePosition,
431                         NodeSourcePosition replaceePosition) {
432             // Replacements cannot have optimistic assumptions since they have
433             // to be valid for the entire run of the VM.
434             final StructuredGraph graph = new StructuredGraph.Builder(replacements.options, debug).method(methodToParse).trackNodeSourcePosition(trackNodeSourcePosition).callerContext(
435                             replaceePosition).build();
436 
437             // Replacements are not user code so they do not participate in unsafe access
438             // tracking
439             graph.disableUnsafeAccessTracking();
440 
441             try (DebugContext.Scope s = debug.scope("buildInitialGraph", graph)) {
442                 MetaAccessProvider metaAccess = replacements.providers.getMetaAccess();
443 
444                 Plugins plugins = new Plugins(replacements.graphBuilderPlugins);
445                 GraphBuilderConfiguration config = GraphBuilderConfiguration.getSnippetDefault(plugins);
446                 if (args != null) {
447                     plugins.prependParameterPlugin(new ConstantBindingParameterPlugin(args, metaAccess, replacements.snippetReflection));
448                 }
449 
450                 IntrinsicContext initialIntrinsicContext = null;
451                 Snippet snippetAnnotation = method.getAnnotation(Snippet.class);
452                 if (snippetAnnotation == null) {
453                     // Post-parse inlined intrinsic
454                     initialIntrinsicContext = new IntrinsicContext(substitutedMethod, method, bytecodeProvider, INLINE_AFTER_PARSING);
455                 } else {
456                     // Snippet
457                     ResolvedJavaMethod original = substitutedMethod != null ? substitutedMethod : method;
458                     initialIntrinsicContext = new IntrinsicContext(original, method, bytecodeProvider, INLINE_AFTER_PARSING, snippetAnnotation.allowPartialIntrinsicArgumentMismatch());
459                 }
460 
461                 createGraphBuilder(metaAccess, replacements.providers.getStampProvider(), replacements.providers.getConstantReflection(), replacements.providers.getConstantFieldProvider(), config,
462                                 OptimisticOptimizations.NONE, initialIntrinsicContext).apply(graph);
463 
464                 new CanonicalizerPhase().apply(graph, new PhaseContext(replacements.providers));
465             } catch (Throwable e) {
466                 throw debug.handle(e);
467             }
468             return graph;
469         }
470 
createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext)471         protected Instance createGraphBuilder(MetaAccessProvider metaAccess, StampProvider stampProvider, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider,
472                         GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) {
473             return new GraphBuilderPhase.Instance(metaAccess, stampProvider, constantReflection, constantFieldProvider, graphBuilderConfig, optimisticOpts,
474                             initialIntrinsicContext);
475         }
476     }
477 
478     @Override
registerSnippetTemplateCache(SnippetTemplateCache templates)479     public void registerSnippetTemplateCache(SnippetTemplateCache templates) {
480         assert snippetTemplateCache.get(templates.getClass().getName()) == null;
481         snippetTemplateCache.put(templates.getClass().getName(), templates);
482     }
483 
484     @Override
getSnippetTemplateCache(Class<T> templatesClass)485     public <T extends SnippetTemplateCache> T getSnippetTemplateCache(Class<T> templatesClass) {
486         SnippetTemplateCache ret = snippetTemplateCache.get(templatesClass.getName());
487         return templatesClass.cast(ret);
488     }
489 }
490