1 /* 2 * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.hotspot; 26 27 import static jdk.vm.ci.runtime.JVMCI.getRuntime; 28 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE; 29 import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE; 30 import static org.graalvm.compiler.core.common.GraalOptions.UseEncodedGraphs; 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 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.HashMap; 38 import java.util.HashSet; 39 import java.util.List; 40 import java.util.Map; 41 import java.util.Objects; 42 import java.util.Set; 43 import java.util.concurrent.ConcurrentHashMap; 44 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.runtime.GraalJVMCICompiler; 50 import org.graalvm.compiler.api.runtime.GraalRuntime; 51 import org.graalvm.compiler.bytecode.BytecodeProvider; 52 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; 53 import org.graalvm.compiler.core.common.type.AbstractObjectStamp; 54 import org.graalvm.compiler.core.common.type.Stamp; 55 import org.graalvm.compiler.core.common.type.StampPair; 56 import org.graalvm.compiler.core.common.type.SymbolicJVMCIReference; 57 import org.graalvm.compiler.debug.DebugContext; 58 import org.graalvm.compiler.debug.GraalError; 59 import org.graalvm.compiler.graph.Node; 60 import org.graalvm.compiler.graph.NodeClass; 61 import org.graalvm.compiler.graph.NodeMap; 62 import org.graalvm.compiler.graph.NodeSourcePosition; 63 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider; 64 import org.graalvm.compiler.hotspot.meta.HotSpotProviders; 65 import org.graalvm.compiler.java.BytecodeParser; 66 import org.graalvm.compiler.java.GraphBuilderPhase; 67 import org.graalvm.compiler.nodeinfo.Verbosity; 68 import org.graalvm.compiler.nodes.CallTargetNode; 69 import org.graalvm.compiler.nodes.Cancellable; 70 import org.graalvm.compiler.nodes.ConstantNode; 71 import org.graalvm.compiler.nodes.EncodedGraph; 72 import org.graalvm.compiler.nodes.FrameState; 73 import org.graalvm.compiler.nodes.FullInfopointNode; 74 import org.graalvm.compiler.nodes.GraphEncoder; 75 import org.graalvm.compiler.nodes.ParameterNode; 76 import org.graalvm.compiler.nodes.ProxyNode; 77 import org.graalvm.compiler.nodes.StructuredGraph; 78 import org.graalvm.compiler.nodes.ValueNode; 79 import org.graalvm.compiler.nodes.cfg.Block; 80 import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin; 81 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration; 82 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 83 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; 84 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; 85 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; 86 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; 87 import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin; 88 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; 89 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin; 90 import org.graalvm.compiler.nodes.java.AccessFieldNode; 91 import org.graalvm.compiler.nodes.java.MethodCallTargetNode; 92 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode; 93 import org.graalvm.compiler.options.OptionValues; 94 import org.graalvm.compiler.phases.OptimisticOptimizations; 95 import org.graalvm.compiler.phases.schedule.SchedulePhase; 96 import org.graalvm.compiler.phases.util.Providers; 97 import org.graalvm.compiler.replacements.ConstantBindingParameterPlugin; 98 import org.graalvm.compiler.replacements.PEGraphDecoder; 99 import org.graalvm.compiler.replacements.ReplacementsImpl; 100 import org.graalvm.compiler.replacements.SnippetCounter; 101 import org.graalvm.compiler.replacements.SnippetIntegerHistogram; 102 103 import jdk.vm.ci.code.TargetDescription; 104 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime; 105 import jdk.vm.ci.hotspot.HotSpotResolvedJavaField; 106 import jdk.vm.ci.hotspot.HotSpotResolvedJavaMethod; 107 import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; 108 import jdk.vm.ci.hotspot.HotSpotSignature; 109 import jdk.vm.ci.meta.Constant; 110 import jdk.vm.ci.meta.ConstantReflectionProvider; 111 import jdk.vm.ci.meta.JavaConstant; 112 import jdk.vm.ci.meta.JavaKind; 113 import jdk.vm.ci.meta.MemoryAccessProvider; 114 import jdk.vm.ci.meta.MethodHandleAccessProvider; 115 import jdk.vm.ci.meta.ResolvedJavaField; 116 import jdk.vm.ci.meta.ResolvedJavaMethod; 117 import jdk.vm.ci.meta.ResolvedJavaType; 118 import jdk.vm.ci.meta.UnresolvedJavaField; 119 import jdk.vm.ci.meta.UnresolvedJavaMethod; 120 import jdk.vm.ci.meta.UnresolvedJavaType; 121 122 /** 123 * This class performs graph encoding using {@link GraphEncoder} but also converts JVMCI type and 124 * method references into a symbolic form that can be resolved at graph decode time using 125 * {@link SymbolicJVMCIReference}. 126 */ 127 public class SymbolicSnippetEncoder { 128 129 /** 130 * This is a customized HotSpotReplacementsImpl intended only for parsing snippets and method 131 * substitutions for graph encoding. 132 */ 133 private final HotSpotSnippetReplacementsImpl snippetReplacements; 134 135 /** 136 * The set of all snippet methods that have been encoded. 137 */ 138 private final Set<ResolvedJavaMethod> snippetMethods = Collections.synchronizedSet(new HashSet<>()); 139 140 /** 141 * A mapping from the method substitution method to the original method name. The string key and 142 * values are produced using {@link #methodKey(ResolvedJavaMethod)}. 143 */ 144 private final Map<String, String> originalMethods = new ConcurrentHashMap<>(); 145 146 private final HotSpotReplacementsImpl originalReplacements; 147 148 /** 149 * The current count of graphs encoded. Used to detect when new graphs have been enqueued for 150 * encoding. 151 */ 152 private int encodedGraphs = 0; 153 154 /** 155 * All the graphs parsed so far. 156 */ 157 private Map<String, StructuredGraph> preparedSnippetGraphs = new HashMap<>(); 158 159 /** 160 * The invocation plugins which were delayed during graph preparation. 161 */ 162 private Set<ResolvedJavaMethod> delayedInvocationPluginMethods = new HashSet<>(); 163 164 void addDelayedInvocationPluginMethod(ResolvedJavaMethod method) { 165 delayedInvocationPluginMethods.add(method); 166 } 167 168 Set<ResolvedJavaMethod> getSnippetMethods() { 169 return snippetMethods; 170 } 171 172 protected class SnippetInlineInvokePlugin implements InlineInvokePlugin { 173 174 @Override 175 public InlineInfo shouldInlineInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) { 176 if (method.getAnnotation(Fold.class) != null) { 177 delayedInvocationPluginMethods.add(method); 178 return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; 179 } 180 181 if (snippetReplacements.getIntrinsifyingPlugin(method) != null) { 182 delayedInvocationPluginMethods.add(method); 183 return InlineInfo.DO_NOT_INLINE_NO_EXCEPTION; 184 } 185 186 // Force inlining when parsing replacements 187 return createIntrinsicInlineInfo(method, snippetReplacements.getDefaultReplacementBytecodeProvider()); 188 } 189 190 @Override 191 public void notifyAfterInline(ResolvedJavaMethod methodToInline) { 192 assert methodToInline.getAnnotation(Fold.class) == null : methodToInline; 193 } 194 } 195 196 public static class SnippetInvocationPlugins extends InvocationPlugins { 197 198 SnippetInvocationPlugins(InvocationPlugins invocationPlugins) { 199 super(invocationPlugins); 200 } 201 202 @Override 203 public InvocationPlugin lookupInvocation(ResolvedJavaMethod method) { 204 if (method.getAnnotation(Fold.class) != null) { 205 return null; 206 } 207 return super.lookupInvocation(method); 208 } 209 } 210 211 /** 212 * This plugin disables the snippet counter machinery. 213 */ 214 private class SnippetCounterPlugin implements NodePlugin { 215 String snippetCounterName = 'L' + SnippetCounter.class.getName().replace('.', '/') + ';'; 216 String snippetIntegerHistogramName = 'L' + SnippetIntegerHistogram.class.getName().replace('.', '/') + ';'; 217 218 @Override 219 public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) { 220 if (field.getName().equals("group") && field.getDeclaringClass().getName().equals(snippetCounterName)) { 221 b.addPush(JavaKind.Object, ConstantNode.forConstant(JavaConstant.NULL_POINTER, b.getMetaAccess())); 222 return true; 223 } 224 if (field.getType().getName().equals(snippetCounterName)) { 225 b.addPush(JavaKind.Object, ConstantNode.forConstant(snippetReplacements.snippetReflection.forObject(SnippetCounter.DISABLED_COUNTER), b.getMetaAccess())); 226 return true; 227 } 228 229 if (field.getType().getName().equals(snippetIntegerHistogramName)) { 230 b.addPush(JavaKind.Object, ConstantNode.forConstant(snippetReplacements.snippetReflection.forObject(SnippetIntegerHistogram.DISABLED_COUNTER), b.getMetaAccess())); 231 return true; 232 } 233 return false; 234 } 235 } 236 237 /** 238 * Generate a String name for a method including all type information. Used as a symbolic key 239 * for lookup. 240 */ 241 private static String methodKey(ResolvedJavaMethod method) { 242 return method.format("%f %H.%n(%P)"); 243 } 244 245 SymbolicSnippetEncoder(HotSpotReplacementsImpl replacements) { 246 this.originalReplacements = replacements; 247 GraphBuilderConfiguration.Plugins plugins = replacements.getGraphBuilderPlugins(); 248 SnippetInvocationPlugins invocationPlugins = new SnippetInvocationPlugins(plugins.getInvocationPlugins()); 249 GraphBuilderConfiguration.Plugins copy = new GraphBuilderConfiguration.Plugins(plugins, invocationPlugins); 250 copy.clearInlineInvokePlugins(); 251 copy.appendInlineInvokePlugin(new SnippetInlineInvokePlugin()); 252 copy.appendNodePlugin(new SnippetCounterPlugin()); 253 HotSpotProviders providers = (HotSpotProviders) replacements.getProviders().copyWith(new HotSpotSubstrateConstantReflectionProvider(replacements.getProviders().getConstantReflection())); 254 this.snippetReplacements = new HotSpotSnippetReplacementsImpl(replacements, providers.copyWith(copy)); 255 this.snippetReplacements.setGraphBuilderPlugins(copy); 256 } 257 258 /** 259 * Compiles the snippet and stores the graph. 260 */ 261 synchronized void registerMethodSubstitution(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, IntrinsicContext.CompilationContext context, OptionValues options) { 262 ResolvedJavaMethod method = plugin.getSubstitute(snippetReplacements.getProviders().getMetaAccess()); 263 assert method.getAnnotation(MethodSubstitution.class) != null : "MethodSubstitution must be annotated with @" + MethodSubstitution.class.getSimpleName(); 264 StructuredGraph subst = buildGraph(method, original, null, true, false, context, options); 265 snippetMethods.add(method); 266 originalMethods.put(methodKey(method), methodKey(original)); 267 preparedSnippetGraphs.put(plugin.toString() + context, subst); 268 } 269 270 static class EncodedSnippets { 271 private byte[] snippetEncoding; 272 private Object[] snippetObjects; 273 private NodeClass<?>[] snippetNodeClasses; 274 private Map<String, Integer> snippetStartOffsets; 275 private Map<String, String> originalMethods; 276 277 EncodedSnippets(byte[] snippetEncoding, Object[] snippetObjects, NodeClass<?>[] snippetNodeClasses, Map<String, Integer> snippetStartOffsets, Map<String, String> originalMethods) { 278 this.snippetEncoding = snippetEncoding; 279 this.snippetObjects = snippetObjects; 280 this.snippetNodeClasses = snippetNodeClasses; 281 this.snippetStartOffsets = snippetStartOffsets; 282 this.originalMethods = originalMethods; 283 } 284 285 StructuredGraph getMethodSubstitutionGraph(MethodSubstitutionPlugin plugin, ResolvedJavaMethod original, ReplacementsImpl replacements, IntrinsicContext.CompilationContext context, 286 StructuredGraph.AllowAssumptions allowAssumptions, Cancellable cancellable, OptionValues options) { 287 Integer startOffset = snippetStartOffsets.get(plugin.toString() + context); 288 if (startOffset == null) { 289 throw GraalError.shouldNotReachHere("plugin graph not found: " + plugin + " with " + context); 290 } 291 292 ResolvedJavaType accessingClass = replacements.getProviders().getMetaAccess().lookupJavaType(plugin.getDeclaringClass()); 293 return decodeGraph(original, accessingClass, startOffset, replacements, context, allowAssumptions, cancellable, options); 294 } 295 296 @SuppressWarnings("try") 297 private StructuredGraph decodeGraph(ResolvedJavaMethod method, 298 ResolvedJavaType accessingClass, 299 int startOffset, 300 ReplacementsImpl replacements, 301 IntrinsicContext.CompilationContext context, 302 StructuredGraph.AllowAssumptions allowAssumptions, 303 Cancellable cancellable, 304 OptionValues options) { 305 Providers providers = replacements.getProviders(); 306 EncodedGraph encodedGraph = new SymbolicEncodedGraph(snippetEncoding, startOffset, snippetObjects, snippetNodeClasses, 307 methodKey(method), accessingClass, method.getDeclaringClass()); 308 try (DebugContext debug = replacements.openDebugContext("SVMSnippet_", method, options)) { 309 StructuredGraph result = new StructuredGraph.Builder(options, debug, allowAssumptions).cancellable(cancellable).method(method).setIsSubstitution(true).build(); 310 PEGraphDecoder graphDecoder = new SubstitutionGraphDecoder(providers, result, replacements, null, method, context, encodedGraph); 311 312 graphDecoder.decode(method, result.isSubstitution(), encodedGraph.trackNodeSourcePosition()); 313 314 assert result.verify(); 315 return result; 316 } 317 } 318 319 StructuredGraph getEncodedSnippet(ResolvedJavaMethod method, ReplacementsImpl replacements, Object[] args, StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) { 320 Integer startOffset = null; 321 if (snippetStartOffsets != null) { 322 startOffset = snippetStartOffsets.get(methodKey(method)); 323 } 324 if (startOffset == null) { 325 if (IS_IN_NATIVE_IMAGE) { 326 throw GraalError.shouldNotReachHere("snippet not found: " + method.format("%H.%n(%p)")); 327 } else { 328 return null; 329 } 330 } 331 332 SymbolicEncodedGraph encodedGraph = new SymbolicEncodedGraph(snippetEncoding, startOffset, snippetObjects, snippetNodeClasses, 333 originalMethods.get(methodKey(method)), method.getDeclaringClass()); 334 return decodeSnippetGraph(encodedGraph, method, replacements, args, allowAssumptions, options); 335 } 336 337 } 338 339 private static class SubstitutionGraphDecoder extends PEGraphDecoder { 340 private final ResolvedJavaMethod method; 341 private final EncodedGraph encodedGraph; 342 private IntrinsicContext intrinsic; 343 344 SubstitutionGraphDecoder(Providers providers, StructuredGraph result, ReplacementsImpl replacements, ParameterPlugin parameterPlugin, ResolvedJavaMethod method, 345 IntrinsicContext.CompilationContext context, EncodedGraph encodedGraph) { 346 super(providers.getCodeCache().getTarget().arch, result, providers, null, 347 replacements.getGraphBuilderPlugins().getInvocationPlugins(), new InlineInvokePlugin[0], parameterPlugin, 348 null, null, null, null); 349 this.method = method; 350 this.encodedGraph = encodedGraph; 351 intrinsic = new IntrinsicContext(method, null, replacements.getDefaultReplacementBytecodeProvider(), context, false); 352 } 353 354 @Override 355 protected EncodedGraph lookupEncodedGraph(ResolvedJavaMethod lookupMethod, 356 MethodSubstitutionPlugin plugin, 357 BytecodeProvider intrinsicBytecodeProvider, 358 boolean isSubstitution, 359 boolean trackNodeSourcePosition) { 360 if (lookupMethod.equals(method)) { 361 return encodedGraph; 362 } else { 363 throw GraalError.shouldNotReachHere(method.format("%H.%n(%p)")); 364 } 365 } 366 367 @Override 368 protected IntrinsicContext getIntrinsic() { 369 return intrinsic; 370 } 371 } 372 373 private StructuredGraph buildGraph(ResolvedJavaMethod method, ResolvedJavaMethod original, Object receiver, boolean requireInlining, boolean trackNodeSourcePosition, 374 IntrinsicContext.CompilationContext context, OptionValues options) { 375 assert method.hasBytecodes() : "Snippet must not be abstract or native"; 376 Object[] args = null; 377 if (receiver != null) { 378 args = new Object[method.getSignature().getParameterCount(true)]; 379 args[0] = receiver; 380 } 381 try (DebugContext debug = openDebugContext("Snippet_", method, options)) { 382 StructuredGraph graph = snippetReplacements.makeGraph(debug, snippetReplacements.getDefaultReplacementBytecodeProvider(), method, args, original, trackNodeSourcePosition, null, context); 383 384 // Check if all methods which should be inlined are really inlined. 385 for (MethodCallTargetNode callTarget : graph.getNodes(MethodCallTargetNode.TYPE)) { 386 ResolvedJavaMethod callee = callTarget.targetMethod(); 387 if (requireInlining && !delayedInvocationPluginMethods.contains(callee) && !Objects.equals(callee, original)) { 388 throw GraalError.shouldNotReachHere("method " + callee.format("%H.%n") + " not inlined in snippet " + method.getName() + " (maybe not final?)"); 389 } 390 } 391 assert verifySnippetEncodeDecode(method, original, trackNodeSourcePosition, graph); 392 debug.dump(DebugContext.VERBOSE_LEVEL, graph, "After buildGraph"); 393 return graph; 394 } 395 } 396 397 @SuppressWarnings("try") 398 private static StructuredGraph decodeSnippetGraph(SymbolicEncodedGraph encodedGraph, ResolvedJavaMethod method, ReplacementsImpl replacements, Object[] args, 399 StructuredGraph.AllowAssumptions allowAssumptions, OptionValues options) { 400 Providers providers = replacements.getProviders(); 401 ParameterPlugin parameterPlugin = null; 402 if (args != null) { 403 parameterPlugin = new ConstantBindingParameterPlugin(args, providers.getMetaAccess(), replacements.snippetReflection); 404 } 405 406 try (DebugContext debug = replacements.openDebugContext("SVMSnippet_", method, options)) { 407 // @formatter:off 408 StructuredGraph result = new StructuredGraph.Builder(options, debug, allowAssumptions) 409 .method(method) 410 .trackNodeSourcePosition(encodedGraph.trackNodeSourcePosition()) 411 .setIsSubstitution(true) 412 .build(); 413 // @formatter:on 414 try (DebugContext.Scope scope = debug.scope("DecodeSnippetGraph", result)) { 415 PEGraphDecoder graphDecoder = new SubstitutionGraphDecoder(providers, result, replacements, parameterPlugin, method, INLINE_AFTER_PARSING, encodedGraph); 416 417 graphDecoder.decode(method, result.isSubstitution(), encodedGraph.trackNodeSourcePosition()); 418 debug.dump(DebugContext.VERBOSE_LEVEL, result, "After decoding"); 419 420 assert result.verify(); 421 return result; 422 } catch (Throwable t) { 423 throw debug.handle(t); 424 } 425 } 426 } 427 428 @SuppressWarnings("try") 429 private boolean verifySnippetEncodeDecode(ResolvedJavaMethod method, ResolvedJavaMethod original, boolean trackNodeSourcePosition, StructuredGraph graph) { 430 // Verify the encoding and decoding process 431 EncodedGraph encodedGraph = GraphEncoder.encodeSingleGraph(graph, HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getTarget().arch); 432 433 try (DebugContext debug = snippetReplacements.openDebugContext("VerifySnippetEncodeDecode_", method, graph.getOptions())) { 434 HotSpotProviders originalProvider = (HotSpotProviders) snippetReplacements.getProviders(); 435 436 SnippetReflectionProvider snippetReflection = originalProvider.getSnippetReflection(); 437 SymbolicSnippetEncoder.HotSpotSubstrateConstantReflectionProvider constantReflection = new SymbolicSnippetEncoder.HotSpotSubstrateConstantReflectionProvider( 438 originalProvider.getConstantReflection()); 439 HotSpotProviders newProviders = new HotSpotProviders(originalProvider.getMetaAccess(), originalProvider.getCodeCache(), constantReflection, 440 originalProvider.getConstantFieldProvider(), originalProvider.getForeignCalls(), originalProvider.getLowerer(), null, originalProvider.getSuites(), 441 originalProvider.getRegisters(), snippetReflection, originalProvider.getWordTypes(), originalProvider.getGraphBuilderPlugins(), originalProvider.getGC()); 442 HotSpotSnippetReplacementsImpl filteringReplacements = new HotSpotSnippetReplacementsImpl(newProviders, snippetReflection, 443 originalProvider.getReplacements().getDefaultReplacementBytecodeProvider(), originalProvider.getCodeCache().getTarget()); 444 filteringReplacements.setGraphBuilderPlugins(originalProvider.getReplacements().getGraphBuilderPlugins()); 445 try (DebugContext.Scope scaope = debug.scope("VerifySnippetEncodeDecode", graph)) { 446 for (int i = 0; i < encodedGraph.getNumObjects(); i++) { 447 filterSnippetObject(encodedGraph.getObject(i)); 448 } 449 StructuredGraph snippet = filteringReplacements.makeGraph(debug, filteringReplacements.getDefaultReplacementBytecodeProvider(), method, null, original, 450 trackNodeSourcePosition, null); 451 SymbolicEncodedGraph symbolicGraph = new SymbolicEncodedGraph(encodedGraph, method.getDeclaringClass(), original != null ? methodKey(original) : null); 452 StructuredGraph decodedSnippet = decodeSnippetGraph(symbolicGraph, original != null ? original : method, originalReplacements, null, 453 StructuredGraph.AllowAssumptions.ifNonNull(graph.getAssumptions()), graph.getOptions()); 454 String snippetString = getCanonicalGraphString(snippet, true, false); 455 String decodedSnippetString = getCanonicalGraphString(decodedSnippet, true, false); 456 if (snippetString.equals(decodedSnippetString)) { 457 debug.log("Snippet decode for %s produces exactly same graph", method); 458 debug.dump(DebugContext.VERBOSE_LEVEL, decodedSnippet, "Decoded snippet graph for %s", method); 459 } else { 460 debug.log("Snippet decode for %s produces different graph", method); 461 debug.log("%s", compareGraphStrings(snippet, snippetString, decodedSnippet, decodedSnippetString)); 462 debug.dump(DebugContext.VERBOSE_LEVEL, snippet, "Snippet graph for %s", method); 463 debug.dump(DebugContext.VERBOSE_LEVEL, graph, "Encoded snippet graph for %s", method); 464 debug.dump(DebugContext.VERBOSE_LEVEL, decodedSnippet, "Decoded snippet graph for %s", method); 465 } 466 } catch (Throwable t) { 467 throw debug.handle(t); 468 } 469 } 470 return true; 471 } 472 473 /** 474 * If there are new graphs waiting to be encoded, reencode all the graphs and return the result. 475 */ 476 @SuppressWarnings("try") 477 private synchronized EncodedSnippets maybeEncodeSnippets(OptionValues options) { 478 Map<String, StructuredGraph> graphs = this.preparedSnippetGraphs; 479 if (encodedGraphs != graphs.size()) { 480 DebugContext debug = openDebugContext("SnippetEncoder", null, options); 481 try (DebugContext.Scope scope = debug.scope("SnippetSupportEncode")) { 482 encodedGraphs = graphs.size(); 483 for (StructuredGraph graph : graphs.values()) { 484 for (Node node : graph.getNodes()) { 485 node.setNodeSourcePosition(null); 486 } 487 } 488 return encodeSnippets(debug); 489 } 490 } 491 return null; 492 } 493 494 synchronized void registerSnippet(ResolvedJavaMethod method, ResolvedJavaMethod original, Object receiver, boolean trackNodeSourcePosition, OptionValues options) { 495 if (IS_BUILDING_NATIVE_IMAGE || UseEncodedGraphs.getValue(options)) { 496 assert method.getAnnotation(Snippet.class) != null : "Snippet must be annotated with @" + Snippet.class.getSimpleName(); 497 String key = methodKey(method); 498 if (!preparedSnippetGraphs.containsKey(key)) { 499 if (original != null) { 500 originalMethods.put(key, methodKey(original)); 501 } 502 StructuredGraph snippet = buildGraph(method, original, receiver, true, trackNodeSourcePosition, INLINE_AFTER_PARSING, options); 503 snippetMethods.add(method); 504 preparedSnippetGraphs.put(key, snippet); 505 } 506 } 507 508 } 509 510 private synchronized EncodedSnippets encodeSnippets(DebugContext debug) { 511 GraphEncoder encoder = new GraphEncoder(HotSpotJVMCIRuntime.runtime().getHostJVMCIBackend().getTarget().arch, debug); 512 for (StructuredGraph graph : preparedSnippetGraphs.values()) { 513 encoder.prepare(graph); 514 } 515 encoder.finishPrepare(); 516 517 byte[] snippetEncoding; 518 Object[] snippetObjects; 519 NodeClass<?>[] snippetNodeClasses; 520 Map<String, Integer> snippetStartOffsets; 521 522 snippetStartOffsets = new HashMap<>(); 523 for (Map.Entry<String, StructuredGraph> entry : preparedSnippetGraphs.entrySet()) { 524 snippetStartOffsets.put(entry.getKey(), encoder.encode(entry.getValue())); 525 } 526 snippetEncoding = encoder.getEncoding(); 527 snippetObjects = encoder.getObjects(); 528 snippetNodeClasses = encoder.getNodeClasses(); 529 for (int i = 0; i < snippetObjects.length; i++) { 530 Object o = filterSnippetObject(snippetObjects[i]); 531 debug.log("snippetObjects[%d] = %s -> %s", i, o != null ? o.getClass().getSimpleName() : null, o); 532 snippetObjects[i] = o; 533 } 534 debug.log("Encoded %d snippet preparedSnippetGraphs using %d bytes with %d objects", snippetStartOffsets.size(), snippetEncoding.length, snippetObjects.length); 535 return new EncodedSnippets(snippetEncoding, snippetObjects, snippetNodeClasses, snippetStartOffsets, originalMethods); 536 } 537 538 /** 539 * Encode any outstanding graphs and return true if any work was done. 540 */ 541 @SuppressWarnings("try") 542 public boolean encode(OptionValues options) { 543 EncodedSnippets encodedSnippets = maybeEncodeSnippets(options); 544 if (encodedSnippets != null) { 545 HotSpotReplacementsImpl.setEncodedSnippets(encodedSnippets); 546 return true; 547 } 548 return false; 549 } 550 551 private DebugContext openDebugContext(String idPrefix, ResolvedJavaMethod method, OptionValues options) { 552 return snippetReplacements.openDebugContext(idPrefix, method, options); 553 } 554 555 static class SymbolicEncodedGraph extends EncodedGraph { 556 557 private final ResolvedJavaType[] accessingClasses; 558 private final String originalMethod; 559 560 SymbolicEncodedGraph(byte[] encoding, int startOffset, Object[] objects, NodeClass<?>[] types, String originalMethod, ResolvedJavaType... accessingClasses) { 561 super(encoding, startOffset, objects, types, null, null, null, false, false); 562 this.accessingClasses = accessingClasses; 563 this.originalMethod = originalMethod; 564 } 565 566 SymbolicEncodedGraph(EncodedGraph encodedGraph, ResolvedJavaType declaringClass, String originalMethod) { 567 this(encodedGraph.getEncoding(), encodedGraph.getStartOffset(), encodedGraph.getObjects(), encodedGraph.getNodeClasses(), 568 originalMethod, declaringClass); 569 } 570 571 @Override 572 public Object getObject(int i) { 573 Object o = objects[i]; 574 Object replacement = null; 575 if (o instanceof SymbolicJVMCIReference) { 576 for (ResolvedJavaType type : accessingClasses) { 577 try { 578 replacement = ((SymbolicJVMCIReference<?>) o).resolve(type); 579 break; 580 } catch (NoClassDefFoundError e) { 581 } 582 } 583 } else if (o instanceof UnresolvedJavaType) { 584 for (ResolvedJavaType type : accessingClasses) { 585 try { 586 replacement = ((UnresolvedJavaType) o).resolve(type); 587 break; 588 } catch (NoClassDefFoundError e) { 589 } 590 } 591 } else if (o instanceof UnresolvedJavaMethod) { 592 throw new InternalError(o.toString()); 593 } else if (o instanceof UnresolvedJavaField) { 594 for (ResolvedJavaType type : accessingClasses) { 595 try { 596 replacement = ((UnresolvedJavaField) o).resolve(type); 597 break; 598 } catch (NoClassDefFoundError e) { 599 } 600 } 601 } else if (o instanceof GraalCapability) { 602 replacement = ((GraalCapability) o).resolve(((GraalJVMCICompiler) getRuntime().getCompiler()).getGraalRuntime()); 603 } else { 604 return o; 605 } 606 if (replacement != null) { 607 objects[i] = o = replacement; 608 } else { 609 throw new GraalError("Can't resolve " + o); 610 } 611 return o; 612 } 613 614 @Override 615 public boolean isCallToOriginal(ResolvedJavaMethod callTarget) { 616 if (originalMethod != null && originalMethod.equals(methodKey(callTarget))) { 617 return true; 618 } 619 return super.isCallToOriginal(callTarget); 620 } 621 } 622 623 /** 624 * Symbolic reference to an object which can be retrieved from 625 * {@link GraalRuntime#getCapability(Class)}. 626 */ 627 static class GraalCapability { 628 final Class<?> capabilityClass; 629 630 GraalCapability(Class<?> capabilityClass) { 631 this.capabilityClass = capabilityClass; 632 } 633 634 public Object resolve(GraalRuntime runtime) { 635 Object capability = runtime.getCapability(this.capabilityClass); 636 if (capability != null) { 637 assert capability.getClass() == capabilityClass; 638 return capability; 639 } 640 throw new InternalError(this.capabilityClass.getName()); 641 } 642 } 643 644 static class SymbolicResolvedJavaMethod implements SymbolicJVMCIReference<ResolvedJavaMethod> { 645 final UnresolvedJavaType type; 646 final String methodName; 647 final String signature; 648 649 SymbolicResolvedJavaMethod(ResolvedJavaMethod method) { 650 this.type = UnresolvedJavaType.create(method.getDeclaringClass().getName()); 651 this.methodName = method.getName(); 652 this.signature = method.getSignature().toMethodDescriptor(); 653 } 654 655 @Override 656 public String toString() { 657 return "SymbolicResolvedJavaMethod{" + 658 "declaringType='" + type.getName() + '\'' + 659 ", methodName='" + methodName + '\'' + 660 ", signature='" + signature + '\'' + 661 '}'; 662 } 663 664 @Override 665 public ResolvedJavaMethod resolve(ResolvedJavaType accessingClass) { 666 ResolvedJavaType resolvedType = type.resolve(accessingClass); 667 if (resolvedType == null) { 668 throw new InternalError("Could not resolve " + this + " in context of " + accessingClass.toJavaName()); 669 } 670 for (ResolvedJavaMethod method : methodName.equals("<init>") ? resolvedType.getDeclaredConstructors() : resolvedType.getDeclaredMethods()) { 671 if (method.getName().equals(methodName) && method.getSignature().toMethodDescriptor().equals(signature)) { 672 return method; 673 } 674 } 675 throw new InternalError("Could not resolve " + this + " in context of " + accessingClass.toJavaName()); 676 } 677 } 678 679 static class SymbolicResolvedJavaField implements SymbolicJVMCIReference<ResolvedJavaField> { 680 final UnresolvedJavaType declaringType; 681 final String name; 682 final UnresolvedJavaType signature; 683 private final boolean isStatic; 684 685 SymbolicResolvedJavaField(ResolvedJavaField field) { 686 this.declaringType = UnresolvedJavaType.create(field.getDeclaringClass().getName()); 687 this.name = field.getName(); 688 this.signature = UnresolvedJavaType.create(field.getType().getName()); 689 this.isStatic = field.isStatic(); 690 } 691 692 @Override 693 public ResolvedJavaField resolve(ResolvedJavaType accessingClass) { 694 ResolvedJavaType resolvedType = declaringType.resolve(accessingClass); 695 ResolvedJavaType resolvedFieldType = signature.resolve(accessingClass); 696 ResolvedJavaField[] fields = isStatic ? resolvedType.getStaticFields() : resolvedType.getInstanceFields(true); 697 for (ResolvedJavaField field : fields) { 698 if (field.getName().equals(name)) { 699 if (field.getType().equals(resolvedFieldType)) { 700 return field; 701 } 702 } 703 } 704 throw new InternalError("Could not resolve " + this + " in context of " + accessingClass.toJavaName()); 705 } 706 707 @Override 708 public String toString() { 709 return "SymbolicResolvedJavaField{" + 710 signature.getName() + ' ' + 711 declaringType.getName() + '.' + 712 name + 713 '}'; 714 } 715 } 716 717 static class SymbolicResolvedJavaMethodBytecode implements SymbolicJVMCIReference<ResolvedJavaMethodBytecode> { 718 SymbolicResolvedJavaMethod method; 719 720 SymbolicResolvedJavaMethodBytecode(ResolvedJavaMethodBytecode bytecode) { 721 method = new SymbolicResolvedJavaMethod(bytecode.getMethod()); 722 } 723 724 @Override 725 public ResolvedJavaMethodBytecode resolve(ResolvedJavaType accessingClass) { 726 return new ResolvedJavaMethodBytecode(method.resolve(accessingClass)); 727 } 728 } 729 730 static class SymbolicStampPair implements SymbolicJVMCIReference<StampPair> { 731 Object trustedStamp; 732 Object uncheckdStamp; 733 734 SymbolicStampPair(StampPair stamp) { 735 this.trustedStamp = maybeMakeSymbolic(stamp.getTrustedStamp()); 736 this.uncheckdStamp = maybeMakeSymbolic(stamp.getUncheckedStamp()); 737 } 738 739 @Override 740 public StampPair resolve(ResolvedJavaType accessingClass) { 741 return StampPair.create(resolveStamp(accessingClass, trustedStamp), resolveStamp(accessingClass, uncheckdStamp)); 742 } 743 } 744 745 private static Object maybeMakeSymbolic(Stamp trustedStamp) { 746 if (trustedStamp != null) { 747 SymbolicJVMCIReference<?> symbolicJVMCIReference = trustedStamp.makeSymbolic(); 748 if (symbolicJVMCIReference != null) { 749 return symbolicJVMCIReference; 750 } 751 } 752 return trustedStamp; 753 } 754 755 private static Stamp resolveStamp(ResolvedJavaType accessingClass, Object stamp) { 756 if (stamp == null) { 757 return null; 758 } 759 if (stamp instanceof Stamp) { 760 return (Stamp) stamp; 761 } 762 return (Stamp) ((SymbolicJVMCIReference<?>) stamp).resolve(accessingClass); 763 } 764 765 public static class HotSpotSubstrateConstantReflectionProvider implements ConstantReflectionProvider { 766 767 private final ConstantReflectionProvider constantReflection; 768 769 HotSpotSubstrateConstantReflectionProvider(ConstantReflectionProvider constantReflection) { 770 this.constantReflection = constantReflection; 771 } 772 773 HashSet<JavaConstant> safeConstants = new HashSet<>(); 774 775 @Override 776 public Boolean constantEquals(Constant x, Constant y) { 777 return constantReflection.constantEquals(x, y); 778 } 779 780 @Override 781 public Integer readArrayLength(JavaConstant array) { 782 return constantReflection.readArrayLength(array); 783 } 784 785 @Override 786 public JavaConstant readArrayElement(JavaConstant array, int index) { 787 return constantReflection.readArrayElement(array, index); 788 } 789 790 @Override 791 public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) { 792 JavaConstant javaConstant = constantReflection.readFieldValue(field, receiver); 793 if (!safeConstants.contains(receiver) && 794 !field.getDeclaringClass().getName().contains("graalvm") && 795 !field.getDeclaringClass().getName().contains("jdk/vm/ci/") && 796 !field.getDeclaringClass().getName().contains("jdk/internal/vm/compiler") && 797 798 !field.getName().equals("TYPE")) { 799 // Only permit constant reflection on compiler classes. This is necessary primarily 800 // because of the boxing snippets which are compiled as snippets but are really just 801 // regular JDK java sources that are being compiled like a snippet. These shouldn't 802 // permit constant folding during graph preparation as that embeds constants from 803 // the runtime into a compiler graph. 804 return null; 805 } 806 if (javaConstant.getJavaKind() == JavaKind.Object) { 807 safeConstants.add(javaConstant); 808 } 809 return javaConstant; 810 } 811 812 @Override 813 public JavaConstant boxPrimitive(JavaConstant source) { 814 return constantReflection.boxPrimitive(source); 815 } 816 817 @Override 818 public JavaConstant unboxPrimitive(JavaConstant source) { 819 return constantReflection.unboxPrimitive(source); 820 } 821 822 @Override 823 public JavaConstant forString(String value) { 824 return constantReflection.forString(value); 825 } 826 827 @Override 828 public ResolvedJavaType asJavaType(Constant constant) { 829 return constantReflection.asJavaType(constant); 830 } 831 832 @Override 833 public MethodHandleAccessProvider getMethodHandleAccess() { 834 return constantReflection.getMethodHandleAccess(); 835 } 836 837 @Override 838 public MemoryAccessProvider getMemoryAccessProvider() { 839 return constantReflection.getMemoryAccessProvider(); 840 } 841 842 @Override 843 public JavaConstant asJavaClass(ResolvedJavaType type) { 844 return constantReflection.asJavaClass(type); 845 } 846 847 @Override 848 public Constant asObjectHub(ResolvedJavaType type) { 849 return constantReflection.asObjectHub(type); 850 } 851 } 852 853 /** 854 * Objects embedded in encoded graphs might need to converted into a symbolic form so convert 855 * the object or pass it through. 856 */ 857 private static Object filterSnippetObject(Object o) { 858 if (o instanceof HotSpotResolvedJavaMethod) { 859 return new SymbolicResolvedJavaMethod((HotSpotResolvedJavaMethod) o); 860 } else if (o instanceof HotSpotResolvedJavaField) { 861 return new SymbolicResolvedJavaField((HotSpotResolvedJavaField) o); 862 } else if (o instanceof HotSpotResolvedJavaType) { 863 return UnresolvedJavaType.create(((ResolvedJavaType) o).getName()); 864 } else if (o instanceof NodeSourcePosition) { 865 // Filter these out for now. These can't easily be handled because these positions 866 // description snippet methods which might not be available in the runtime. 867 return null; 868 } else if (o instanceof HotSpotForeignCallsProvider || o instanceof GraalHotSpotVMConfig) { 869 return new GraalCapability(o.getClass()); 870 } else if (o instanceof Stamp) { 871 SymbolicJVMCIReference<?> ref = ((Stamp) o).makeSymbolic(); 872 if (ref != null) { 873 return ref; 874 } 875 return o; 876 } else if (o instanceof StampPair) { 877 if (((StampPair) o).getTrustedStamp() instanceof AbstractObjectStamp) { 878 return new SymbolicStampPair((StampPair) o); 879 } 880 } else if (o instanceof ResolvedJavaMethodBytecode) { 881 return new SymbolicResolvedJavaMethodBytecode((ResolvedJavaMethodBytecode) o); 882 } else if (o instanceof HotSpotSignature) { 883 throw new GraalError(o.toString()); 884 } 885 return o; 886 } 887 888 private static String compareGraphStrings(StructuredGraph expectedGraph, String expectedString, StructuredGraph actualGraph, String actualString) { 889 if (!expectedString.equals(actualString)) { 890 String[] expectedLines = expectedString.split("\n"); 891 String[] actualLines = actualString.split("\n"); 892 int diffIndex = -1; 893 int limit = Math.min(actualLines.length, expectedLines.length); 894 String marker = " <<<"; 895 for (int i = 0; i < limit; i++) { 896 if (!expectedLines[i].equals(actualLines[i])) { 897 diffIndex = i; 898 break; 899 } 900 } 901 if (diffIndex == -1) { 902 // Prefix is the same so add some space after the prefix 903 diffIndex = limit; 904 if (actualLines.length == limit) { 905 actualLines = Arrays.copyOf(actualLines, limit + 1); 906 actualLines[diffIndex] = ""; 907 } else { 908 assert expectedLines.length == limit; 909 expectedLines = Arrays.copyOf(expectedLines, limit + 1); 910 expectedLines[diffIndex] = ""; 911 } 912 } 913 // Place a marker next to the first line that differs 914 expectedLines[diffIndex] = expectedLines[diffIndex] + marker; 915 actualLines[diffIndex] = actualLines[diffIndex] + marker; 916 String ediff = String.join("\n", expectedLines); 917 String adiff = String.join("\n", actualLines); 918 return "mismatch in preparedSnippetGraphs:\n========= expected (" + expectedGraph + ") =========\n" + ediff + "\n\n========= actual (" + actualGraph + ") =========\n" + adiff; 919 } else { 920 return "mismatch in preparedSnippetGraphs"; 921 } 922 } 923 924 private static String getCanonicalGraphString(StructuredGraph graph, boolean excludeVirtual, boolean checkConstants) { 925 SchedulePhase schedule = new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST); 926 schedule.apply(graph); 927 StructuredGraph.ScheduleResult scheduleResult = graph.getLastSchedule(); 928 929 NodeMap<Integer> canonicalId = graph.createNodeMap(); 930 int nextId = 0; 931 932 List<String> constantsLines = new ArrayList<>(); 933 934 StringBuilder result = new StringBuilder(); 935 for (Block block : scheduleResult.getCFG().getBlocks()) { 936 result.append("Block ").append(block).append(' '); 937 if (block == scheduleResult.getCFG().getStartBlock()) { 938 result.append("* "); 939 } 940 result.append("-> "); 941 for (Block succ : block.getSuccessors()) { 942 result.append(succ).append(' '); 943 } 944 result.append('\n'); 945 for (Node node : scheduleResult.getBlockToNodesMap().get(block)) { 946 if (node instanceof ValueNode && node.isAlive()) { 947 if (!excludeVirtual || !(node instanceof VirtualObjectNode || node instanceof ProxyNode || node instanceof FullInfopointNode || node instanceof ParameterNode)) { 948 if (node instanceof ConstantNode) { 949 if (checkConstants) { 950 String name = node.toString(Verbosity.Name); 951 if (excludeVirtual) { 952 constantsLines.add(name); 953 } else { 954 constantsLines.add(name + " (" + filteredUsageCount(node) + ")"); 955 } 956 } 957 } else { 958 int id; 959 if (canonicalId.get(node) != null) { 960 id = canonicalId.get(node); 961 } else { 962 id = nextId++; 963 canonicalId.set(node, id); 964 } 965 String name = node.getClass().getSimpleName(); 966 result.append(" ").append(id).append('|').append(name); 967 if (node instanceof AccessFieldNode) { 968 result.append('#'); 969 result.append(((AccessFieldNode) node).field()); 970 } 971 if (!excludeVirtual) { 972 result.append(" ("); 973 result.append(filteredUsageCount(node)); 974 result.append(')'); 975 } 976 result.append('\n'); 977 } 978 } 979 } 980 } 981 } 982 983 StringBuilder constantsLinesResult = new StringBuilder(); 984 if (checkConstants) { 985 constantsLinesResult.append(constantsLines.size()).append(" constants:\n"); 986 } 987 Collections.sort(constantsLines); 988 for (String s : constantsLines) { 989 constantsLinesResult.append(s); 990 constantsLinesResult.append('\n'); 991 } 992 993 return constantsLinesResult.toString() + result.toString(); 994 } 995 996 private static int filteredUsageCount(Node node) { 997 return node.usages().filter(n -> !(n instanceof FrameState)).count(); 998 } 999 1000 /** 1001 * This horror show of classes exists solely get {@link HotSpotSnippetBytecodeParser} to be used 1002 * as the parser for these snippets. 1003 */ 1004 static class HotSpotSnippetReplacementsImpl extends HotSpotReplacementsImpl { 1005 HotSpotSnippetReplacementsImpl(HotSpotReplacementsImpl replacements, Providers providers) { 1006 super(replacements, providers); 1007 } 1008 1009 HotSpotSnippetReplacementsImpl(Providers providers, SnippetReflectionProvider snippetReflection, BytecodeProvider bytecodeProvider, TargetDescription target) { 1010 super(providers, snippetReflection, bytecodeProvider, target); 1011 } 1012 1013 @Override 1014 protected GraphMaker createGraphMaker(ResolvedJavaMethod substitute, ResolvedJavaMethod original) { 1015 return new SnippetGraphMaker(this, substitute, original); 1016 } 1017 } 1018 1019 static class SnippetGraphMaker extends ReplacementsImpl.GraphMaker { 1020 SnippetGraphMaker(ReplacementsImpl replacements, ResolvedJavaMethod substitute, ResolvedJavaMethod substitutedMethod) { 1021 super(replacements, substitute, substitutedMethod); 1022 } 1023 1024 @Override 1025 protected GraphBuilderPhase.Instance createGraphBuilder(Providers providers, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, 1026 IntrinsicContext initialIntrinsicContext) { 1027 return new HotSpotSnippetGraphBuilderPhase(providers, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); 1028 } 1029 } 1030 1031 static class HotSpotSnippetGraphBuilderPhase extends GraphBuilderPhase.Instance { 1032 HotSpotSnippetGraphBuilderPhase(Providers theProviders, GraphBuilderConfiguration graphBuilderConfig, OptimisticOptimizations optimisticOpts, IntrinsicContext initialIntrinsicContext) { 1033 super(theProviders, graphBuilderConfig, optimisticOpts, initialIntrinsicContext); 1034 } 1035 1036 @Override 1037 protected BytecodeParser createBytecodeParser(StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, IntrinsicContext intrinsicContext) { 1038 return new HotSpotSnippetBytecodeParser(this, graph, parent, method, entryBCI, intrinsicContext); 1039 } 1040 } 1041 1042 static class HotSpotSnippetBytecodeParser extends BytecodeParser { 1043 HotSpotSnippetBytecodeParser(GraphBuilderPhase.Instance graphBuilderInstance, StructuredGraph graph, BytecodeParser parent, ResolvedJavaMethod method, int entryBCI, 1044 IntrinsicContext intrinsicContext) { 1045 super(graphBuilderInstance, graph, parent, method, entryBCI, intrinsicContext); 1046 } 1047 1048 @Override 1049 public boolean canDeferPlugin(GeneratedInvocationPlugin plugin) { 1050 // Fold is always deferred but NodeIntrinsics may have to wait if all their arguments 1051 // aren't constant yet. 1052 return plugin.isGeneratedFromFoldOrNodeIntrinsic(); 1053 } 1054 1055 @Override 1056 protected boolean canInlinePartialIntrinsicExit() { 1057 return false; 1058 } 1059 1060 @Override 1061 protected boolean tryInvocationPlugin(CallTargetNode.InvokeKind invokeKind, ValueNode[] args, ResolvedJavaMethod targetMethod, JavaKind resultType) { 1062 if (intrinsicContext != null && intrinsicContext.isCallToOriginal(targetMethod)) { 1063 return false; 1064 } 1065 if (targetMethod.getAnnotation(Fold.class) != null) { 1066 // Always defer Fold until decode time but NodeIntrinsics may fold if they are able. 1067 return false; 1068 } 1069 return super.tryInvocationPlugin(invokeKind, args, targetMethod, resultType); 1070 } 1071 } 1072 }