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