1 /* 2 * Copyright (c) 2015, 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 org.graalvm.compiler.debug.GraalError.unimplemented; 28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; 29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; 30 31 import java.net.URI; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.Formatter; 35 import java.util.HashMap; 36 import java.util.List; 37 import java.util.Map; 38 39 import jdk.internal.vm.compiler.collections.EconomicMap; 40 import jdk.internal.vm.compiler.collections.Equivalence; 41 import org.graalvm.compiler.api.replacements.Fold; 42 import org.graalvm.compiler.bytecode.Bytecode; 43 import org.graalvm.compiler.bytecode.BytecodeProvider; 44 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode; 45 import org.graalvm.compiler.core.common.PermanentBailoutException; 46 import org.graalvm.compiler.core.common.cfg.CFGVerifier; 47 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider; 48 import org.graalvm.compiler.core.common.type.Stamp; 49 import org.graalvm.compiler.core.common.type.StampFactory; 50 import org.graalvm.compiler.core.common.type.StampPair; 51 import org.graalvm.compiler.debug.DebugCloseable; 52 import org.graalvm.compiler.debug.DebugContext; 53 import org.graalvm.compiler.debug.GraalError; 54 import org.graalvm.compiler.graph.Node; 55 import org.graalvm.compiler.graph.Node.NodeIntrinsic; 56 import org.graalvm.compiler.graph.NodeClass; 57 import org.graalvm.compiler.graph.NodeSourcePosition; 58 import org.graalvm.compiler.graph.SourceLanguagePosition; 59 import org.graalvm.compiler.graph.SourceLanguagePositionProvider; 60 import org.graalvm.compiler.graph.spi.Canonicalizable; 61 import org.graalvm.compiler.java.GraphBuilderPhase; 62 import org.graalvm.compiler.nodeinfo.NodeInfo; 63 import org.graalvm.compiler.nodes.AbstractBeginNode; 64 import org.graalvm.compiler.nodes.AbstractMergeNode; 65 import org.graalvm.compiler.nodes.CallTargetNode; 66 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; 67 import org.graalvm.compiler.nodes.ControlSinkNode; 68 import org.graalvm.compiler.nodes.DeoptimizeNode; 69 import org.graalvm.compiler.nodes.EncodedGraph; 70 import org.graalvm.compiler.nodes.FixedNode; 71 import org.graalvm.compiler.nodes.FixedWithNextNode; 72 import org.graalvm.compiler.nodes.FrameState; 73 import org.graalvm.compiler.nodes.IfNode; 74 import org.graalvm.compiler.nodes.Invoke; 75 import org.graalvm.compiler.nodes.InvokeWithExceptionNode; 76 import org.graalvm.compiler.nodes.MergeNode; 77 import org.graalvm.compiler.nodes.NodeView; 78 import org.graalvm.compiler.nodes.ParameterNode; 79 import org.graalvm.compiler.nodes.ReturnNode; 80 import org.graalvm.compiler.nodes.SimplifyingGraphDecoder; 81 import org.graalvm.compiler.nodes.StateSplit; 82 import org.graalvm.compiler.nodes.StructuredGraph; 83 import org.graalvm.compiler.nodes.UnwindNode; 84 import org.graalvm.compiler.nodes.ValueNode; 85 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 86 import org.graalvm.compiler.nodes.extended.ForeignCallNode; 87 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; 88 import org.graalvm.compiler.nodes.graphbuilderconf.GeneratedInvocationPlugin; 89 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext; 90 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin; 91 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo; 92 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext; 93 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin; 94 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins; 95 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver; 96 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin; 97 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind; 98 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin; 99 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin; 100 import org.graalvm.compiler.nodes.java.LoadFieldNode; 101 import org.graalvm.compiler.nodes.java.LoadIndexedNode; 102 import org.graalvm.compiler.nodes.java.MethodCallTargetNode; 103 import org.graalvm.compiler.nodes.java.MonitorIdNode; 104 import org.graalvm.compiler.nodes.java.NewArrayNode; 105 import org.graalvm.compiler.nodes.java.NewInstanceNode; 106 import org.graalvm.compiler.nodes.java.NewMultiArrayNode; 107 import org.graalvm.compiler.nodes.java.StoreFieldNode; 108 import org.graalvm.compiler.nodes.java.StoreIndexedNode; 109 import org.graalvm.compiler.nodes.spi.CoreProviders; 110 import org.graalvm.compiler.nodes.spi.Replacements; 111 import org.graalvm.compiler.nodes.spi.StampProvider; 112 import org.graalvm.compiler.nodes.type.StampTool; 113 import org.graalvm.compiler.nodes.util.GraphUtil; 114 import org.graalvm.compiler.options.Option; 115 import org.graalvm.compiler.options.OptionKey; 116 import org.graalvm.compiler.options.OptionType; 117 import org.graalvm.compiler.options.OptionValues; 118 import org.graalvm.compiler.phases.common.inlining.InliningUtil; 119 120 import jdk.vm.ci.code.Architecture; 121 import jdk.vm.ci.code.BailoutException; 122 import jdk.vm.ci.code.BytecodeFrame; 123 import jdk.vm.ci.meta.Assumptions; 124 import jdk.vm.ci.meta.ConstantReflectionProvider; 125 import jdk.vm.ci.meta.DeoptimizationAction; 126 import jdk.vm.ci.meta.DeoptimizationReason; 127 import jdk.vm.ci.meta.JavaConstant; 128 import jdk.vm.ci.meta.JavaKind; 129 import jdk.vm.ci.meta.JavaType; 130 import jdk.vm.ci.meta.MetaAccessProvider; 131 import jdk.vm.ci.meta.ResolvedJavaField; 132 import jdk.vm.ci.meta.ResolvedJavaMethod; 133 import jdk.vm.ci.meta.ResolvedJavaType; 134 135 /** 136 * A graph decoder that performs partial evaluation, i.e., that performs method inlining and 137 * canonicalization/simplification of nodes during decoding. 138 * 139 * Inlining and loop explosion are configured via the plugin mechanism also used by the 140 * {@link GraphBuilderPhase}. However, not all callback methods defined in 141 * {@link GraphBuilderContext} are available since decoding is more limited than graph building. 142 * 143 * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to 144 * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and 145 * {@link IntegerSwitchNode switches} with constant conditions are simplified. 146 */ 147 public abstract class PEGraphDecoder extends SimplifyingGraphDecoder { 148 149 private static final Object CACHED_NULL_VALUE = new Object(); 150 151 public static class Options { 152 @Option(help = "Maximum inlining depth during partial evaluation before reporting an infinite recursion")// 153 public static final OptionKey<Integer> InliningDepthError = new OptionKey<>(1000); 154 155 @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)// 156 public static final OptionKey<Integer> MaximumLoopExplosionCount = new OptionKey<>(10000); 157 158 @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug)// 159 public static final OptionKey<Boolean> FailedLoopExplosionIsFatal = new OptionKey<>(false); 160 } 161 162 protected class PEMethodScope extends MethodScope { 163 /** The state of the caller method. Only non-null during method inlining. */ 164 protected final PEMethodScope caller; 165 protected final ResolvedJavaMethod method; 166 protected final InvokeData invokeData; 167 protected final int inliningDepth; 168 169 protected final ValueNode[] arguments; 170 private SourceLanguagePosition sourceLanguagePosition = UnresolvedSourceLanguagePosition.INSTANCE; 171 172 protected FrameState outerState; 173 protected FrameState exceptionState; 174 protected ExceptionPlaceholderNode exceptionPlaceholderNode; 175 protected NodeSourcePosition callerBytecodePosition; 176 177 protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData, 178 int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, ValueNode[] arguments) { 179 super(callerLoopScope, targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin)); 180 181 this.caller = caller; 182 this.method = method; 183 this.invokeData = invokeData; 184 this.inliningDepth = inliningDepth; 185 this.arguments = arguments; 186 } 187 188 @Override 189 public boolean isInlinedMethod() { 190 return caller != null; 191 } 192 193 @Override 194 public NodeSourcePosition getCallerBytecodePosition(NodeSourcePosition position) { 195 if (caller == null) { 196 return position; 197 } 198 if (callerBytecodePosition == null) { 199 NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition(); 200 if (invokePosition == null) { 201 assert position == null : "should only happen when tracking is disabled"; 202 return null; 203 } 204 callerBytecodePosition = invokePosition; 205 } 206 if (position != null) { 207 return position.addCaller(caller.resolveSourceLanguagePosition(), callerBytecodePosition); 208 } 209 final SourceLanguagePosition pos = caller.resolveSourceLanguagePosition(); 210 if (pos != null && callerBytecodePosition != null) { 211 return new NodeSourcePosition(pos, callerBytecodePosition.getCaller(), callerBytecodePosition.getMethod(), callerBytecodePosition.getBCI()); 212 } 213 return callerBytecodePosition; 214 } 215 216 private SourceLanguagePosition resolveSourceLanguagePosition() { 217 SourceLanguagePosition res = sourceLanguagePosition; 218 if (res == UnresolvedSourceLanguagePosition.INSTANCE) { 219 res = null; 220 if (arguments != null && method.hasReceiver() && arguments.length > 0 && arguments[0].isJavaConstant()) { 221 JavaConstant constantArgument = arguments[0].asJavaConstant(); 222 res = sourceLanguagePositionProvider.getPosition(constantArgument); 223 } 224 sourceLanguagePosition = res; 225 } 226 return res; 227 } 228 } 229 230 private static final class UnresolvedSourceLanguagePosition implements SourceLanguagePosition { 231 static final SourceLanguagePosition INSTANCE = new UnresolvedSourceLanguagePosition(); 232 233 @Override 234 public String toShortString() { 235 throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable."); 236 } 237 238 @Override 239 public int getOffsetEnd() { 240 throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable."); 241 } 242 243 @Override 244 public int getOffsetStart() { 245 throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable."); 246 } 247 248 @Override 249 public int getLineNumber() { 250 throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable."); 251 } 252 253 @Override 254 public URI getURI() { 255 throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable."); 256 } 257 258 @Override 259 public String getLanguage() { 260 throw new IllegalStateException(getClass().getSimpleName() + " should not be reachable."); 261 } 262 } 263 264 protected class PENonAppendGraphBuilderContext implements GraphBuilderContext { 265 protected final PEMethodScope methodScope; 266 protected final Invoke invoke; 267 268 @Override 269 public ExternalInliningContext getExternalInliningContext() { 270 return new ExternalInliningContext() { 271 @Override 272 public int getInlinedDepth() { 273 int count = 0; 274 PEGraphDecoder.PEMethodScope scope = methodScope; 275 while (scope != null) { 276 if (scope.method.equals(callInlinedMethod)) { 277 count++; 278 } 279 scope = scope.caller; 280 } 281 return count; 282 } 283 }; 284 } 285 286 public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) { 287 this.methodScope = methodScope; 288 this.invoke = invoke; 289 } 290 291 /** 292 * {@link Fold} and {@link NodeIntrinsic} can be deferred during parsing/decoding. Only by 293 * the end of {@linkplain SnippetTemplate#instantiate Snippet instantiation} do they need to 294 * have been processed. 295 * 296 * This is how SVM handles snippets. They are parsed with plugins disabled and then encoded 297 * and stored in the image. When the snippet is needed at runtime the graph is decoded and 298 * the plugins are run during the decoding process. If they aren't handled at this point 299 * then they will never be handled. 300 */ 301 @Override 302 public boolean canDeferPlugin(GeneratedInvocationPlugin plugin) { 303 return plugin.getSource().equals(Fold.class) || plugin.getSource().equals(Node.NodeIntrinsic.class); 304 } 305 306 @Override 307 public BailoutException bailout(String string) { 308 BailoutException bailout = new PermanentBailoutException(string); 309 throw GraphUtil.createBailoutException(string, bailout, GraphUtil.approxSourceStackTraceElement(methodScope.getCallerBytecodePosition())); 310 } 311 312 @Override 313 public StampProvider getStampProvider() { 314 return providers.getStampProvider(); 315 } 316 317 @Override 318 public MetaAccessProvider getMetaAccess() { 319 return providers.getMetaAccess(); 320 } 321 322 @Override 323 public ConstantReflectionProvider getConstantReflection() { 324 return providers.getConstantReflection(); 325 } 326 327 @Override 328 public ConstantFieldProvider getConstantFieldProvider() { 329 return providers.getConstantFieldProvider(); 330 } 331 332 @Override 333 public Replacements getReplacements() { 334 return providers.getReplacements(); 335 } 336 337 @Override 338 public StructuredGraph getGraph() { 339 return graph; 340 } 341 342 @Override 343 public int getDepth() { 344 return methodScope.inliningDepth; 345 } 346 347 @Override 348 public IntrinsicContext getIntrinsic() { 349 return null; 350 } 351 352 @Override 353 public <T extends ValueNode> T append(T value) { 354 throw unimplemented(); 355 } 356 357 @Override 358 public void push(JavaKind kind, ValueNode value) { 359 throw unimplemented(); 360 } 361 362 @Override 363 public Invoke handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) { 364 throw unimplemented(); 365 } 366 367 @Override 368 public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) { 369 throw unimplemented(); 370 } 371 372 @Override 373 public boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) { 374 return false; 375 } 376 377 @Override 378 public void setStateAfter(StateSplit stateSplit) { 379 throw unimplemented(); 380 } 381 382 @Override 383 public GraphBuilderContext getParent() { 384 throw unimplemented(); 385 } 386 387 @Override 388 public Bytecode getCode() { 389 throw unimplemented(); 390 } 391 392 @Override 393 public ResolvedJavaMethod getMethod() { 394 throw unimplemented(); 395 } 396 397 @Override 398 public int bci() { 399 return invoke.bci(); 400 } 401 402 @Override 403 public InvokeKind getInvokeKind() { 404 throw unimplemented(); 405 } 406 407 @Override 408 public JavaType getInvokeReturnType() { 409 throw unimplemented(); 410 } 411 412 @Override 413 public String toString() { 414 Formatter fmt = new Formatter(); 415 PEMethodScope scope = this.methodScope; 416 fmt.format("%s", new ResolvedJavaMethodBytecode(scope.method).asStackTraceElement(invoke.bci())); 417 NodeSourcePosition callers = scope.getCallerBytecodePosition(); 418 if (callers != null) { 419 fmt.format("%n%s", callers); 420 } 421 return fmt.toString(); 422 } 423 } 424 425 protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext { 426 protected FixedWithNextNode lastInstr; 427 protected ValueNode pushedNode; 428 protected boolean invokeConsumed; 429 protected final InvokeKind invokeKind; 430 protected final JavaType invokeReturnType; 431 432 public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) { 433 this(inlineScope, lastInstr, null, null); 434 } 435 436 public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr, InvokeKind invokeKind, JavaType invokeReturnType) { 437 super(inlineScope, inlineScope.invokeData != null ? inlineScope.invokeData.invoke : null); 438 this.lastInstr = lastInstr; 439 this.invokeKind = invokeKind; 440 this.invokeReturnType = invokeReturnType; 441 } 442 443 @Override 444 public void push(JavaKind kind, ValueNode value) { 445 if (pushedNode != null) { 446 throw unimplemented("Only one push is supported"); 447 } 448 pushedNode = value; 449 } 450 451 @Override 452 public void setStateAfter(StateSplit stateSplit) { 453 Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); 454 getGraph().add(stateAfter); 455 FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter); 456 stateSplit.setStateAfter(fs); 457 } 458 459 @SuppressWarnings("try") 460 @Override 461 public <T extends ValueNode> T append(T v) { 462 if (v.graph() != null) { 463 return v; 464 } 465 try (DebugCloseable position = withNodeSoucePosition()) { 466 T added = getGraph().addOrUniqueWithInputs(v); 467 if (added == v) { 468 updateLastInstruction(v); 469 } 470 return added; 471 } 472 } 473 474 private DebugCloseable withNodeSoucePosition() { 475 if (getGraph().trackNodeSourcePosition()) { 476 NodeSourcePosition callerBytecodePosition = methodScope.getCallerBytecodePosition(); 477 if (callerBytecodePosition != null) { 478 return getGraph().withNodeSourcePosition(callerBytecodePosition); 479 } 480 } 481 return null; 482 } 483 484 private <T extends ValueNode> void updateLastInstruction(T v) { 485 if (v instanceof FixedNode) { 486 FixedNode fixedNode = (FixedNode) v; 487 if (lastInstr != null) { 488 lastInstr.setNext(fixedNode); 489 } 490 if (fixedNode instanceof FixedWithNextNode) { 491 FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode; 492 assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end"; 493 lastInstr = fixedWithNextNode; 494 } else { 495 lastInstr = null; 496 } 497 } 498 } 499 500 @Override 501 public InvokeKind getInvokeKind() { 502 if (invokeKind != null) { 503 return invokeKind; 504 } 505 return super.getInvokeKind(); 506 } 507 508 @Override 509 public JavaType getInvokeReturnType() { 510 if (invokeReturnType != null) { 511 return invokeReturnType; 512 } 513 return super.getInvokeReturnType(); 514 } 515 516 @Override 517 public void handleReplacedInvoke(CallTargetNode callTarget, JavaKind resultType) { 518 if (invokeConsumed) { 519 throw unimplemented("handleReplacedInvoke can be called only once"); 520 } 521 invokeConsumed = true; 522 523 appendInvoke(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData, callTarget); 524 updateLastInstruction(invoke.asNode()); 525 } 526 } 527 528 @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) 529 static class ExceptionPlaceholderNode extends ValueNode { 530 public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class); 531 532 protected ExceptionPlaceholderNode() { 533 super(TYPE, StampFactory.object()); 534 } 535 } 536 537 protected static class SpecialCallTargetCacheKey { 538 private final InvokeKind invokeKind; 539 private final ResolvedJavaMethod targetMethod; 540 private final ResolvedJavaType contextType; 541 private final Stamp receiverStamp; 542 543 public SpecialCallTargetCacheKey(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ResolvedJavaType contextType, Stamp receiverStamp) { 544 this.invokeKind = invokeKind; 545 this.targetMethod = targetMethod; 546 this.contextType = contextType; 547 this.receiverStamp = receiverStamp; 548 } 549 550 @Override 551 public int hashCode() { 552 return invokeKind.hashCode() ^ targetMethod.hashCode() ^ contextType.hashCode() ^ receiverStamp.hashCode(); 553 } 554 555 @Override 556 public boolean equals(Object obj) { 557 if (obj instanceof SpecialCallTargetCacheKey) { 558 SpecialCallTargetCacheKey key = (SpecialCallTargetCacheKey) obj; 559 return key.invokeKind.equals(this.invokeKind) && key.targetMethod.equals(this.targetMethod) && key.contextType.equals(this.contextType) && key.receiverStamp.equals(this.receiverStamp); 560 } 561 return false; 562 } 563 } 564 565 private final LoopExplosionPlugin loopExplosionPlugin; 566 private final InvocationPlugins invocationPlugins; 567 private final InlineInvokePlugin[] inlineInvokePlugins; 568 private final ParameterPlugin parameterPlugin; 569 private final NodePlugin[] nodePlugins; 570 private final EconomicMap<SpecialCallTargetCacheKey, Object> specialCallTargetCache; 571 private final EconomicMap<ResolvedJavaMethod, Object> invocationPluginCache; 572 private final ResolvedJavaMethod callInlinedMethod; 573 protected final SourceLanguagePositionProvider sourceLanguagePositionProvider; 574 575 public PEGraphDecoder(Architecture architecture, StructuredGraph graph, CoreProviders providers, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, 576 InlineInvokePlugin[] inlineInvokePlugins, 577 ParameterPlugin parameterPlugin, 578 NodePlugin[] nodePlugins, ResolvedJavaMethod callInlinedMethod, SourceLanguagePositionProvider sourceLanguagePositionProvider) { 579 super(architecture, graph, providers, true); 580 this.loopExplosionPlugin = loopExplosionPlugin; 581 this.invocationPlugins = invocationPlugins; 582 this.inlineInvokePlugins = inlineInvokePlugins; 583 this.parameterPlugin = parameterPlugin; 584 this.nodePlugins = nodePlugins; 585 this.specialCallTargetCache = EconomicMap.create(Equivalence.DEFAULT); 586 this.invocationPluginCache = EconomicMap.create(Equivalence.DEFAULT); 587 this.callInlinedMethod = callInlinedMethod; 588 this.sourceLanguagePositionProvider = sourceLanguagePositionProvider; 589 } 590 591 protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) { 592 if (loopExplosionPlugin == null) { 593 return LoopExplosionKind.NONE; 594 } else { 595 return loopExplosionPlugin.loopExplosionKind(method); 596 } 597 } 598 599 @SuppressWarnings("try") 600 public void decode(ResolvedJavaMethod method, boolean isSubstitution, boolean trackNodeSourcePosition) { 601 try (DebugContext.Scope scope = debug.scope("PEGraphDecode", graph)) { 602 EncodedGraph encodedGraph = lookupEncodedGraph(method, null, null, isSubstitution, trackNodeSourcePosition); 603 PEMethodScope methodScope = new PEMethodScope(graph, null, null, encodedGraph, method, null, 0, loopExplosionPlugin, null); 604 decode(createInitialLoopScope(methodScope, null)); 605 cleanupGraph(methodScope); 606 607 debug.dump(DebugContext.VERBOSE_LEVEL, graph, "After graph cleanup"); 608 assert graph.verify(); 609 } catch (Throwable t) { 610 throw debug.handle(t); 611 } 612 613 try { 614 /* Check that the control flow graph can be computed, to catch problems early. */ 615 assert CFGVerifier.verify(ControlFlowGraph.compute(graph, true, true, true, true)); 616 } catch (Throwable ex) { 617 throw GraalError.shouldNotReachHere("Control flow graph not valid after partial evaluation"); 618 } 619 } 620 621 @Override 622 protected void cleanupGraph(MethodScope methodScope) { 623 super.cleanupGraph(methodScope); 624 625 for (FrameState frameState : graph.getNodes(FrameState.TYPE)) { 626 if (frameState.bci == BytecodeFrame.UNWIND_BCI) { 627 /* 628 * handleMissingAfterExceptionFrameState is called during graph decoding from 629 * InliningUtil.processFrameState - but during graph decoding it does not do 630 * anything because the usages of the frameState are not available yet. So we need 631 * to call it again. 632 */ 633 PEMethodScope peMethodScope = (PEMethodScope) methodScope; 634 Invoke invoke = peMethodScope.invokeData != null ? peMethodScope.invokeData.invoke : null; 635 InliningUtil.handleMissingAfterExceptionFrameState(frameState, invoke, null, true); 636 637 /* 638 * The frameState must be gone now, because it is not a valid deoptimization point. 639 */ 640 assert frameState.isDeleted(); 641 } 642 } 643 } 644 645 @Override 646 protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) { 647 PEMethodScope methodScope = (PEMethodScope) s; 648 649 if (loopScope.loopIteration > Options.MaximumLoopExplosionCount.getValue(options)) { 650 throw tooManyLoopExplosionIterations(methodScope, options); 651 } 652 } 653 654 private static RuntimeException tooManyLoopExplosionIterations(PEMethodScope methodScope, OptionValues options) { 655 String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?"; 656 RuntimeException bailout = Options.FailedLoopExplosionIsFatal.getValue(options) ? new RuntimeException(message) : new PermanentBailoutException(message); 657 throw GraphUtil.createBailoutException(message, bailout, GraphUtil.approxSourceStackTraceElement(methodScope.getCallerBytecodePosition())); 658 } 659 660 @Override 661 protected LoopScope handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) { 662 PEMethodScope methodScope = (PEMethodScope) s; 663 664 /* 665 * Decode the call target, but do not add it to the graph yet. This avoids adding usages for 666 * all the arguments, which are expensive to remove again when we can inline the method. 667 */ 668 assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; 669 CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId); 670 if (callTarget instanceof MethodCallTargetNode) { 671 MethodCallTargetNode methodCall = (MethodCallTargetNode) callTarget; 672 if (methodCall.invokeKind().hasReceiver()) { 673 invokeData.constantReceiver = methodCall.arguments().get(0).asJavaConstant(); 674 NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition(); 675 if (invokeData.constantReceiver != null && invokePosition != null) { 676 // new NodeSourcePosition(invokeData.constantReceiver, 677 // invokePosition.getCaller(), invokePosition.getMethod(), 678 // invokePosition.getBCI()); 679 } 680 } 681 LoopScope inlineLoopScope = trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget); 682 if (inlineLoopScope != null) { 683 return inlineLoopScope; 684 } 685 } 686 687 /* We know that we need an invoke, so now we can add the call target to the graph. */ 688 graph.add(callTarget); 689 registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false); 690 return super.handleInvoke(methodScope, loopScope, invokeData); 691 } 692 693 protected LoopScope trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { 694 // attempt to devirtualize the call 695 ResolvedJavaMethod specialCallTarget = getSpecialCallTarget(invokeData, callTarget); 696 if (specialCallTarget != null) { 697 callTarget.setTargetMethod(specialCallTarget); 698 callTarget.setInvokeKind(InvokeKind.Special); 699 } 700 701 if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) { 702 /* 703 * The invocation plugin handled the call, so decoding continues in the calling method. 704 */ 705 return loopScope; 706 } 707 LoopScope inlineLoopScope = tryInline(methodScope, loopScope, invokeData, callTarget); 708 if (inlineLoopScope != null) { 709 /* 710 * We can inline the call, so decoding continues in the inlined method. 711 */ 712 return inlineLoopScope; 713 } 714 715 for (InlineInvokePlugin plugin : inlineInvokePlugins) { 716 plugin.notifyNotInlined(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke); 717 } 718 return null; 719 } 720 721 private ResolvedJavaMethod getSpecialCallTarget(InvokeData invokeData, MethodCallTargetNode callTarget) { 722 if (callTarget.invokeKind().isDirect()) { 723 return null; 724 } 725 726 // check for trivial cases (e.g. final methods, nonvirtual methods) 727 if (callTarget.targetMethod().canBeStaticallyBound()) { 728 return callTarget.targetMethod(); 729 } 730 731 SpecialCallTargetCacheKey key = new SpecialCallTargetCacheKey(callTarget.invokeKind(), callTarget.targetMethod(), invokeData.contextType, callTarget.receiver().stamp(NodeView.DEFAULT)); 732 Object specialCallTarget = specialCallTargetCache.get(key); 733 if (specialCallTarget == null) { 734 specialCallTarget = MethodCallTargetNode.devirtualizeCall(key.invokeKind, key.targetMethod, key.contextType, graph.getAssumptions(), 735 key.receiverStamp); 736 if (specialCallTarget == null) { 737 specialCallTarget = CACHED_NULL_VALUE; 738 } 739 specialCallTargetCache.put(key, specialCallTarget); 740 } 741 742 return specialCallTarget == CACHED_NULL_VALUE ? null : (ResolvedJavaMethod) specialCallTarget; 743 } 744 745 protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { 746 if (invocationPlugins == null || invocationPlugins.isEmpty()) { 747 return false; 748 } 749 750 Invoke invoke = invokeData.invoke; 751 752 ResolvedJavaMethod targetMethod = callTarget.targetMethod(); 753 if (loopScope.methodScope.encodedGraph.isCallToOriginal(targetMethod)) { 754 return false; 755 } 756 757 InvocationPlugin invocationPlugin = getInvocationPlugin(targetMethod); 758 if (invocationPlugin == null) { 759 return false; 760 } 761 762 if (loopScope.methodScope.encodedGraph.isCallToOriginal(targetMethod)) { 763 return false; 764 } 765 766 ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); 767 FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor(); 768 769 /* 770 * Remove invoke from graph so that invocation plugin can append nodes to the predecessor. 771 */ 772 invoke.asNode().replaceAtPredecessor(null); 773 774 PEMethodScope inlineScope = new PEMethodScope(graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, loopExplosionPlugin, arguments); 775 776 JavaType returnType = targetMethod.getSignature().getReturnType(methodScope.method.getDeclaringClass()); 777 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor, callTarget.invokeKind(), returnType); 778 InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext); 779 780 if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) { 781 782 if (graphBuilderContext.invokeConsumed) { 783 /* Nothing to do. */ 784 } else if (graphBuilderContext.lastInstr != null) { 785 registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true); 786 invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode); 787 graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(graphBuilderContext.lastInstr))); 788 deleteInvoke(invoke); 789 } else { 790 assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?"; 791 invoke.asNode().replaceAtUsages(null); 792 deleteInvoke(invoke); 793 } 794 return true; 795 796 } else { 797 /* Intrinsification failed, restore original state: invoke is in Graph. */ 798 invokePredecessor.setNext(invoke.asNode()); 799 return false; 800 } 801 } 802 803 private InvocationPlugin getInvocationPlugin(ResolvedJavaMethod targetMethod) { 804 Object invocationPlugin = invocationPluginCache.get(targetMethod); 805 if (invocationPlugin == null) { 806 invocationPlugin = invocationPlugins.lookupInvocation(targetMethod); 807 if (invocationPlugin == null) { 808 invocationPlugin = CACHED_NULL_VALUE; 809 } 810 invocationPluginCache.put(targetMethod, invocationPlugin); 811 } 812 813 return invocationPlugin == CACHED_NULL_VALUE ? null : (InvocationPlugin) invocationPlugin; 814 } 815 816 protected LoopScope tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) { 817 if (!callTarget.invokeKind().isDirect()) { 818 return null; 819 } 820 821 ResolvedJavaMethod targetMethod = callTarget.targetMethod(); 822 if (targetMethod.hasNeverInlineDirective()) { 823 return null; 824 } 825 826 ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]); 827 GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke); 828 829 for (InlineInvokePlugin plugin : inlineInvokePlugins) { 830 InlineInfo inlineInfo = plugin.shouldInlineInvoke(graphBuilderContext, targetMethod, arguments); 831 if (inlineInfo != null) { 832 if (inlineInfo.getMethodToInline() == null) { 833 return null; 834 } else { 835 return doInline(methodScope, loopScope, invokeData, inlineInfo, arguments); 836 } 837 } 838 } 839 return null; 840 } 841 842 protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, InlineInfo inlineInfo, ValueNode[] arguments) { 843 if (!invokeData.invoke.useForInlining()) { 844 return null; 845 } 846 ResolvedJavaMethod inlineMethod = inlineInfo.getMethodToInline(); 847 ResolvedJavaMethod originalMethod = inlineInfo.getOriginalMethod(); 848 boolean isSubstitution = originalMethod != null && !originalMethod.equals(inlineMethod); 849 EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, originalMethod, inlineInfo.getIntrinsicBytecodeProvider(), isSubstitution, graph.trackNodeSourcePosition()); 850 if (graphToInline == null) { 851 return null; 852 } 853 854 assert !graph.trackNodeSourcePosition() || graphToInline.trackNodeSourcePosition() : graph + " " + graphToInline; 855 if (methodScope.inliningDepth > Options.InliningDepthError.getValue(options)) { 856 throw tooDeepInlining(methodScope); 857 } 858 859 for (InlineInvokePlugin plugin : inlineInvokePlugins) { 860 plugin.notifyBeforeInline(inlineMethod); 861 } 862 863 Invoke invoke = invokeData.invoke; 864 FixedNode invokeNode = invoke.asNode(); 865 FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor(); 866 invokeNode.replaceAtPredecessor(null); 867 868 PEMethodScope inlineScope = new PEMethodScope(graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1, 869 loopExplosionPlugin, arguments); 870 871 if (!inlineMethod.isStatic()) { 872 if (StampTool.isPointerAlwaysNull(arguments[0])) { 873 /* 874 * The receiver is null, so we can unconditionally throw a NullPointerException 875 * instead of performing any inlining. 876 */ 877 DeoptimizeNode deoptimizeNode = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.NullCheckException)); 878 predecessor.setNext(deoptimizeNode); 879 finishInlining(inlineScope); 880 /* Continue decoding in the caller. */ 881 return loopScope; 882 883 } else if (!StampTool.isPointerNonNull(arguments[0])) { 884 /* The receiver might be null, so we need to insert a null check. */ 885 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, predecessor); 886 arguments[0] = graphBuilderContext.nullCheckedValue(arguments[0]); 887 predecessor = graphBuilderContext.lastInstr; 888 } 889 } 890 891 LoopScope inlineLoopScope = createInitialLoopScope(inlineScope, predecessor); 892 893 /* 894 * The GraphEncoder assigns parameters a nodeId immediately after the fixed nodes. 895 * Initializing createdNodes here avoid decoding and immediately replacing the 896 * ParameterNodes. 897 */ 898 int firstArgumentNodeId = inlineScope.maxFixedNodeOrderId + 1; 899 for (int i = 0; i < arguments.length; i++) { 900 inlineLoopScope.createdNodes[firstArgumentNodeId + i] = arguments[i]; 901 } 902 903 // Copy assumptions from inlinee to caller 904 Assumptions assumptions = graph.getAssumptions(); 905 Assumptions inlinedAssumptions = graphToInline.getAssumptions(); 906 if (assumptions != null) { 907 if (inlinedAssumptions != null) { 908 assumptions.record(inlinedAssumptions); 909 } 910 } else { 911 assert inlinedAssumptions == null : String.format("cannot inline graph (%s) which makes assumptions into a graph (%s) that doesn't", inlineMethod, graph); 912 } 913 914 // Copy inlined methods from inlinee to caller 915 List<ResolvedJavaMethod> inlinedMethods = graphToInline.getInlinedMethods(); 916 if (inlinedMethods != null) { 917 for (ResolvedJavaMethod other : inlinedMethods) { 918 graph.recordMethod(other); 919 } 920 } 921 922 if (graphToInline.getFields() != null) { 923 for (ResolvedJavaField field : graphToInline.getFields()) { 924 graph.recordField(field); 925 } 926 } 927 if (graphToInline.hasUnsafeAccess()) { 928 graph.markUnsafeAccess(); 929 } 930 931 /* 932 * Do the actual inlining by returning the initial loop scope for the inlined method scope. 933 */ 934 return inlineLoopScope; 935 } 936 937 @Override 938 protected void finishInlining(MethodScope is) { 939 PEMethodScope inlineScope = (PEMethodScope) is; 940 ResolvedJavaMethod inlineMethod = inlineScope.method; 941 PEMethodScope methodScope = inlineScope.caller; 942 LoopScope loopScope = inlineScope.callerLoopScope; 943 InvokeData invokeData = inlineScope.invokeData; 944 Invoke invoke = invokeData.invoke; 945 FixedNode invokeNode = invoke.asNode(); 946 947 ValueNode exceptionValue = null; 948 int returnNodeCount = 0; 949 int unwindNodeCount = 0; 950 List<ControlSinkNode> returnAndUnwindNodes = inlineScope.returnAndUnwindNodes; 951 for (int i = 0; i < returnAndUnwindNodes.size(); i++) { 952 FixedNode fixedNode = returnAndUnwindNodes.get(i); 953 if (fixedNode instanceof ReturnNode) { 954 returnNodeCount++; 955 } else if (fixedNode.isAlive()) { 956 assert fixedNode instanceof UnwindNode; 957 unwindNodeCount++; 958 } 959 } 960 961 if (unwindNodeCount > 0) { 962 FixedNode unwindReplacement; 963 if (invoke instanceof InvokeWithExceptionNode) { 964 /* Decoding continues for the exception handler. */ 965 unwindReplacement = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId); 966 } else { 967 /* No exception handler available, so the only thing we can do is deoptimize. */ 968 unwindReplacement = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler)); 969 } 970 971 if (unwindNodeCount == 1) { 972 /* Only one UnwindNode, we can use the exception directly. */ 973 UnwindNode unwindNode = getSingleMatchingNode(returnAndUnwindNodes, returnNodeCount > 0, UnwindNode.class); 974 exceptionValue = unwindNode.exception(); 975 unwindNode.replaceAndDelete(unwindReplacement); 976 977 } else { 978 /* 979 * More than one UnwindNode. This can happen with the loop explosion strategy 980 * FULL_EXPLODE_UNTIL_RETURN, where we keep exploding after the loop and therefore 981 * also explode exception paths. Merge the exception in a similar way as multiple 982 * return values. 983 */ 984 MergeNode unwindMergeNode = graph.add(new MergeNode()); 985 exceptionValue = InliningUtil.mergeValueProducers(unwindMergeNode, getMatchingNodes(returnAndUnwindNodes, returnNodeCount > 0, UnwindNode.class, unwindNodeCount), 986 null, unwindNode -> unwindNode.exception()); 987 unwindMergeNode.setNext(unwindReplacement); 988 989 ensureExceptionStateDecoded(inlineScope); 990 unwindMergeNode.setStateAfter(inlineScope.exceptionState.duplicateModified(JavaKind.Object, JavaKind.Object, exceptionValue)); 991 } 992 } 993 994 assert invoke.next() == null; 995 assert !(invoke instanceof InvokeWithExceptionNode) || ((InvokeWithExceptionNode) invoke).exceptionEdge() == null; 996 997 ValueNode returnValue; 998 if (returnNodeCount == 0) { 999 returnValue = null; 1000 } else if (returnNodeCount == 1) { 1001 ReturnNode returnNode = getSingleMatchingNode(returnAndUnwindNodes, unwindNodeCount > 0, ReturnNode.class); 1002 returnValue = returnNode.result(); 1003 FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode)); 1004 returnNode.replaceAndDelete(n); 1005 } else { 1006 AbstractMergeNode merge = graph.add(new MergeNode()); 1007 merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); 1008 returnValue = InliningUtil.mergeReturns(merge, getMatchingNodes(returnAndUnwindNodes, unwindNodeCount > 0, ReturnNode.class, returnNodeCount)); 1009 FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge); 1010 merge.setNext(n); 1011 } 1012 invokeNode.replaceAtUsages(returnValue); 1013 1014 /* 1015 * Usage the handles that we have on the return value and the exception to update the 1016 * orderId->Node table. 1017 */ 1018 registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true); 1019 if (invoke instanceof InvokeWithExceptionNode) { 1020 registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true); 1021 } 1022 if (inlineScope.exceptionPlaceholderNode != null) { 1023 inlineScope.exceptionPlaceholderNode.replaceAtUsagesAndDelete(exceptionValue); 1024 } 1025 deleteInvoke(invoke); 1026 1027 for (InlineInvokePlugin plugin : inlineInvokePlugins) { 1028 plugin.notifyAfterInline(inlineMethod); 1029 } 1030 } 1031 1032 @SuppressWarnings("unchecked") 1033 private static <T> T getSingleMatchingNode(List<ControlSinkNode> returnAndUnwindNodes, boolean hasNonMatchingEntries, Class<T> clazz) { 1034 if (!hasNonMatchingEntries) { 1035 assert returnAndUnwindNodes.size() == 1; 1036 return (T) returnAndUnwindNodes.get(0); 1037 } 1038 1039 for (int i = 0; i < returnAndUnwindNodes.size(); i++) { 1040 ControlSinkNode node = returnAndUnwindNodes.get(i); 1041 if (clazz.isInstance(node)) { 1042 return (T) node; 1043 } 1044 } 1045 throw GraalError.shouldNotReachHere(); 1046 } 1047 1048 @SuppressWarnings("unchecked") 1049 private static <T> List<T> getMatchingNodes(List<ControlSinkNode> returnAndUnwindNodes, boolean hasNonMatchingEntries, Class<T> clazz, int resultCount) { 1050 if (!hasNonMatchingEntries) { 1051 return (List<T>) returnAndUnwindNodes; 1052 } 1053 1054 List<T> result = new ArrayList<>(resultCount); 1055 for (int i = 0; i < returnAndUnwindNodes.size(); i++) { 1056 ControlSinkNode node = returnAndUnwindNodes.get(i); 1057 if (clazz.isInstance(node)) { 1058 result.add((T) node); 1059 } 1060 } 1061 assert result.size() == resultCount; 1062 return result; 1063 } 1064 1065 private static RuntimeException tooDeepInlining(PEMethodScope methodScope) { 1066 HashMap<ResolvedJavaMethod, Integer> methodCounts = new HashMap<>(); 1067 for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) { 1068 Integer oldCount = methodCounts.get(cur.method); 1069 methodCounts.put(cur.method, oldCount == null ? 1 : oldCount + 1); 1070 } 1071 1072 List<Map.Entry<ResolvedJavaMethod, Integer>> methods = new ArrayList<>(methodCounts.entrySet()); 1073 methods.sort((e1, e2) -> -Integer.compare(e1.getValue(), e2.getValue())); 1074 1075 StringBuilder msg = new StringBuilder("Too deep inlining, probably caused by recursive inlining.").append(System.lineSeparator()).append("== Inlined methods ordered by inlining frequency:"); 1076 for (Map.Entry<ResolvedJavaMethod, Integer> entry : methods) { 1077 msg.append(System.lineSeparator()).append(entry.getKey().format("%H.%n(%p) [")).append(entry.getValue()).append("]"); 1078 } 1079 msg.append(System.lineSeparator()).append("== Complete stack trace of inlined methods:"); 1080 int lastBci = 0; 1081 for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) { 1082 msg.append(System.lineSeparator()).append(cur.method.asStackTraceElement(lastBci)); 1083 if (cur.invokeData != null) { 1084 lastBci = cur.invokeData.invoke.bci(); 1085 } else { 1086 lastBci = 0; 1087 } 1088 } 1089 1090 throw new PermanentBailoutException(msg.toString()); 1091 } 1092 1093 public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, AbstractBeginNode lastBlock) { 1094 assert lastBlock.isAlive(); 1095 FixedNode n; 1096 if (invokeData.invoke instanceof InvokeWithExceptionNode) { 1097 registerNode(loopScope, invokeData.nextOrderId, lastBlock, false, false); 1098 n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId); 1099 } else { 1100 n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId); 1101 } 1102 return n; 1103 } 1104 1105 private static void deleteInvoke(Invoke invoke) { 1106 /* 1107 * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can 1108 * kill too much: nodes that are decoded later can use values that appear unused by now. 1109 */ 1110 FrameState frameState = invoke.stateAfter(); 1111 invoke.asNode().safeDelete(); 1112 assert invoke.callTarget() == null : "must not have been added to the graph yet"; 1113 if (frameState != null && frameState.hasNoUsages()) { 1114 frameState.safeDelete(); 1115 } 1116 } 1117 1118 protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, ResolvedJavaMethod originalMethod, BytecodeProvider intrinsicBytecodeProvider, boolean isSubstitution, 1119 boolean trackNodeSourcePosition); 1120 1121 @Override 1122 protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) { 1123 PEMethodScope methodScope = (PEMethodScope) s; 1124 1125 if (node instanceof ForeignCallNode) { 1126 ForeignCallNode foreignCall = (ForeignCallNode) node; 1127 if (foreignCall.getBci() == BytecodeFrame.UNKNOWN_BCI && methodScope.invokeData != null) { 1128 foreignCall.setBci(methodScope.invokeData.invoke.bci()); 1129 } 1130 } 1131 1132 super.handleFixedNode(methodScope, loopScope, nodeOrderId, node); 1133 } 1134 1135 @SuppressWarnings("try") 1136 @Override 1137 protected Node canonicalizeFixedNode(MethodScope s, Node node) { 1138 PEMethodScope methodScope = (PEMethodScope) s; 1139 1140 Node replacedNode = node; 1141 if (nodePlugins != null && nodePlugins.length > 0) { 1142 if (node instanceof LoadFieldNode) { 1143 LoadFieldNode loadFieldNode = (LoadFieldNode) node; 1144 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, loadFieldNode); 1145 ResolvedJavaField field = loadFieldNode.field(); 1146 if (loadFieldNode.isStatic()) { 1147 for (NodePlugin nodePlugin : nodePlugins) { 1148 if (nodePlugin.handleLoadStaticField(graphBuilderContext, field)) { 1149 replacedNode = graphBuilderContext.pushedNode; 1150 break; 1151 } 1152 } 1153 } else { 1154 ValueNode object = loadFieldNode.object(); 1155 for (NodePlugin nodePlugin : nodePlugins) { 1156 if (nodePlugin.handleLoadField(graphBuilderContext, object, field)) { 1157 replacedNode = graphBuilderContext.pushedNode; 1158 break; 1159 } 1160 } 1161 } 1162 } else if (node instanceof StoreFieldNode) { 1163 StoreFieldNode storeFieldNode = (StoreFieldNode) node; 1164 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, storeFieldNode); 1165 ResolvedJavaField field = storeFieldNode.field(); 1166 if (storeFieldNode.isStatic()) { 1167 ValueNode value = storeFieldNode.value(); 1168 for (NodePlugin nodePlugin : nodePlugins) { 1169 if (nodePlugin.handleStoreStaticField(graphBuilderContext, field, value)) { 1170 replacedNode = graphBuilderContext.pushedNode; 1171 break; 1172 } 1173 } 1174 } else { 1175 ValueNode object = storeFieldNode.object(); 1176 ValueNode value = storeFieldNode.value(); 1177 for (NodePlugin nodePlugin : nodePlugins) { 1178 if (nodePlugin.handleStoreField(graphBuilderContext, object, field, value)) { 1179 replacedNode = graphBuilderContext.pushedNode; 1180 break; 1181 } 1182 } 1183 } 1184 } else if (node instanceof LoadIndexedNode) { 1185 LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node; 1186 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, loadIndexedNode); 1187 ValueNode array = loadIndexedNode.array(); 1188 ValueNode index = loadIndexedNode.index(); 1189 for (NodePlugin nodePlugin : nodePlugins) { 1190 if (nodePlugin.handleLoadIndexed(graphBuilderContext, array, index, loadIndexedNode.getBoundsCheck(), loadIndexedNode.elementKind())) { 1191 replacedNode = graphBuilderContext.pushedNode; 1192 break; 1193 } 1194 } 1195 } else if (node instanceof StoreIndexedNode) { 1196 StoreIndexedNode storeIndexedNode = (StoreIndexedNode) node; 1197 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, storeIndexedNode); 1198 ValueNode array = storeIndexedNode.array(); 1199 ValueNode index = storeIndexedNode.index(); 1200 ValueNode value = storeIndexedNode.value(); 1201 for (NodePlugin nodePlugin : nodePlugins) { 1202 if (nodePlugin.handleStoreIndexed(graphBuilderContext, array, index, storeIndexedNode.getBoundsCheck(), storeIndexedNode.getStoreCheck(), storeIndexedNode.elementKind(), value)) { 1203 replacedNode = graphBuilderContext.pushedNode; 1204 break; 1205 } 1206 } 1207 } else if (node instanceof NewInstanceNode) { 1208 NewInstanceNode newInstanceNode = (NewInstanceNode) node; 1209 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, newInstanceNode); 1210 ResolvedJavaType type = newInstanceNode.instanceClass(); 1211 for (NodePlugin nodePlugin : nodePlugins) { 1212 if (nodePlugin.handleNewInstance(graphBuilderContext, type)) { 1213 replacedNode = graphBuilderContext.pushedNode; 1214 break; 1215 } 1216 } 1217 } else if (node instanceof NewArrayNode) { 1218 NewArrayNode newArrayNode = (NewArrayNode) node; 1219 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, newArrayNode); 1220 ResolvedJavaType elementType = newArrayNode.elementType(); 1221 ValueNode length = newArrayNode.length(); 1222 for (NodePlugin nodePlugin : nodePlugins) { 1223 if (nodePlugin.handleNewArray(graphBuilderContext, elementType, length)) { 1224 replacedNode = graphBuilderContext.pushedNode; 1225 break; 1226 } 1227 } 1228 } else if (node instanceof NewMultiArrayNode) { 1229 NewMultiArrayNode newArrayNode = (NewMultiArrayNode) node; 1230 PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(methodScope, newArrayNode); 1231 ResolvedJavaType elementType = newArrayNode.type(); 1232 ValueNode[] dimensions = newArrayNode.dimensions().toArray(new ValueNode[0]); 1233 for (NodePlugin nodePlugin : nodePlugins) { 1234 if (nodePlugin.handleNewMultiArray(graphBuilderContext, elementType, dimensions)) { 1235 replacedNode = graphBuilderContext.pushedNode; 1236 break; 1237 } 1238 } 1239 } 1240 } 1241 1242 return super.canonicalizeFixedNode(methodScope, replacedNode); 1243 } 1244 1245 @Override 1246 protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node n) { 1247 PEMethodScope methodScope = (PEMethodScope) s; 1248 1249 Node node = n; 1250 if (node instanceof ParameterNode) { 1251 ParameterNode param = (ParameterNode) node; 1252 if (methodScope.isInlinedMethod()) { 1253 throw GraalError.shouldNotReachHere("Parameter nodes are already registered when the inlined scope is created"); 1254 1255 } else if (parameterPlugin != null) { 1256 assert !methodScope.isInlinedMethod(); 1257 GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null); 1258 Node result = parameterPlugin.interceptParameter(graphBuilderContext, param.index(), 1259 StampPair.create(param.stamp(NodeView.DEFAULT), param.uncheckedStamp())); 1260 if (result != null) { 1261 return result; 1262 } 1263 } 1264 node = param.copyWithInputs(); 1265 } 1266 1267 return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node); 1268 } 1269 1270 protected void ensureOuterStateDecoded(PEMethodScope methodScope) { 1271 if (methodScope.outerState == null && methodScope.caller != null) { 1272 FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter(); 1273 if (stateAtReturn == null) { 1274 stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId); 1275 } 1276 1277 JavaKind invokeReturnKind = methodScope.invokeData.invoke.asNode().getStackKind(); 1278 FrameState outerState = stateAtReturn.duplicateModified(graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind, null, null); 1279 1280 /* 1281 * When the encoded graph has methods inlining, we can already have a proper caller 1282 * state. If not, we set the caller state here. 1283 */ 1284 if (outerState.outerFrameState() == null && methodScope.caller != null) { 1285 ensureOuterStateDecoded(methodScope.caller); 1286 outerState.setOuterFrameState(methodScope.caller.outerState); 1287 } 1288 methodScope.outerState = outerState; 1289 } 1290 } 1291 1292 protected void ensureStateAfterDecoded(PEMethodScope methodScope) { 1293 if (methodScope.invokeData.invoke.stateAfter() == null) { 1294 methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId)); 1295 } 1296 } 1297 1298 protected void ensureExceptionStateDecoded(PEMethodScope methodScope) { 1299 if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) { 1300 ensureStateAfterDecoded(methodScope); 1301 1302 assert methodScope.exceptionPlaceholderNode == null; 1303 methodScope.exceptionPlaceholderNode = graph.add(new ExceptionPlaceholderNode()); 1304 registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false); 1305 FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId); 1306 1307 if (exceptionState.outerFrameState() == null && methodScope.caller != null) { 1308 ensureOuterStateDecoded(methodScope.caller); 1309 exceptionState.setOuterFrameState(methodScope.caller.outerState); 1310 } 1311 methodScope.exceptionState = exceptionState; 1312 } 1313 } 1314 1315 @Override 1316 protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) { 1317 PEMethodScope methodScope = (PEMethodScope) s; 1318 1319 if (methodScope.isInlinedMethod()) { 1320 if (node instanceof FrameState) { 1321 FrameState frameState = (FrameState) node; 1322 1323 ensureOuterStateDecoded(methodScope); 1324 if (frameState.bci < 0) { 1325 ensureExceptionStateDecoded(methodScope); 1326 } 1327 List<ValueNode> invokeArgsList = null; 1328 if (frameState.bci == BytecodeFrame.BEFORE_BCI) { 1329 /* 1330 * We know that the argument list is only used in this case, so avoid the List 1331 * allocation for "normal" bcis. 1332 */ 1333 invokeArgsList = Arrays.asList(methodScope.arguments); 1334 } 1335 return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, null, methodScope.method, methodScope.exceptionState, methodScope.outerState, true, 1336 methodScope.method, invokeArgsList); 1337 1338 } else if (node instanceof MonitorIdNode) { 1339 ensureOuterStateDecoded(methodScope); 1340 InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node); 1341 return node; 1342 } 1343 } 1344 1345 return node; 1346 } 1347 }