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