1 /*
   2  * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.replacements;
  24 
  25 import static org.graalvm.compiler.debug.GraalError.unimplemented;
  26 import static org.graalvm.compiler.java.BytecodeParserOptions.DumpDuringGraphBuilding;
  27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
  28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
  29 
  30 import java.util.ArrayList;
  31 import java.util.Arrays;
  32 import java.util.HashMap;
  33 import java.util.Iterator;
  34 import java.util.List;
  35 import java.util.Map;
  36 
  37 import org.graalvm.compiler.bytecode.Bytecode;
  38 import org.graalvm.compiler.bytecode.BytecodeProvider;
  39 import org.graalvm.compiler.common.PermanentBailoutException;
  40 import org.graalvm.compiler.core.common.cfg.CFGVerifier;
  41 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
  42 import org.graalvm.compiler.core.common.type.StampFactory;
  43 import org.graalvm.compiler.core.common.type.StampPair;
  44 import org.graalvm.compiler.debug.Debug;
  45 import org.graalvm.compiler.debug.DebugCloseable;
  46 import org.graalvm.compiler.debug.GraalError;
  47 import org.graalvm.compiler.graph.Node;
  48 import org.graalvm.compiler.graph.NodeClass;
  49 import org.graalvm.compiler.graph.NodeSourcePosition;
  50 import org.graalvm.compiler.graph.spi.Canonicalizable;
  51 import org.graalvm.compiler.java.GraphBuilderPhase;
  52 import org.graalvm.compiler.nodeinfo.NodeInfo;
  53 import org.graalvm.compiler.nodes.AbstractBeginNode;
  54 import org.graalvm.compiler.nodes.AbstractMergeNode;
  55 import org.graalvm.compiler.nodes.CallTargetNode;
  56 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
  57 import org.graalvm.compiler.nodes.DeoptimizeNode;
  58 import org.graalvm.compiler.nodes.EncodedGraph;
  59 import org.graalvm.compiler.nodes.FixedNode;
  60 import org.graalvm.compiler.nodes.FixedWithNextNode;
  61 import org.graalvm.compiler.nodes.FrameState;
  62 import org.graalvm.compiler.nodes.IfNode;
  63 import org.graalvm.compiler.nodes.Invoke;
  64 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
  65 import org.graalvm.compiler.nodes.MergeNode;
  66 import org.graalvm.compiler.nodes.ParameterNode;
  67 import org.graalvm.compiler.nodes.ReturnNode;
  68 import org.graalvm.compiler.nodes.SimplifyingGraphDecoder;
  69 import org.graalvm.compiler.nodes.StateSplit;
  70 import org.graalvm.compiler.nodes.StructuredGraph;
  71 import org.graalvm.compiler.nodes.UnwindNode;
  72 import org.graalvm.compiler.nodes.ValueNode;
  73 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
  74 import org.graalvm.compiler.nodes.extended.ForeignCallNode;
  75 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
  76 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
  77 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
  78 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin.InlineInfo;
  79 import org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext;
  80 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
  81 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
  82 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.InvocationPluginReceiver;
  83 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin;
  84 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind;
  85 import org.graalvm.compiler.nodes.graphbuilderconf.ParameterPlugin;
  86 import org.graalvm.compiler.nodes.java.MethodCallTargetNode;
  87 import org.graalvm.compiler.nodes.java.MonitorIdNode;
  88 import org.graalvm.compiler.nodes.spi.StampProvider;
  89 import org.graalvm.compiler.nodes.util.GraphUtil;
  90 import org.graalvm.compiler.options.Option;
  91 import org.graalvm.compiler.options.OptionType;
  92 import org.graalvm.compiler.options.OptionValue;
  93 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
  94 
  95 import jdk.vm.ci.code.Architecture;
  96 import jdk.vm.ci.code.BailoutException;
  97 import jdk.vm.ci.code.BytecodeFrame;
  98 import jdk.vm.ci.meta.ConstantReflectionProvider;
  99 import jdk.vm.ci.meta.DeoptimizationAction;
 100 import jdk.vm.ci.meta.DeoptimizationReason;
 101 import jdk.vm.ci.meta.JavaConstant;
 102 import jdk.vm.ci.meta.JavaKind;
 103 import jdk.vm.ci.meta.JavaType;
 104 import jdk.vm.ci.meta.MetaAccessProvider;
 105 import jdk.vm.ci.meta.ResolvedJavaMethod;
 106 
 107 /**
 108  * A graph decoder that performs partial evaluation, i.e., that performs method inlining and
 109  * canonicalization/simplification of nodes during decoding.
 110  *
 111  * Inlining and loop explosion are configured via the plugin mechanism also used by the
 112  * {@link GraphBuilderPhase}. However, not all callback methods defined in
 113  * {@link GraphBuilderContext} are available since decoding is more limited than graph building.
 114  *
 115  * The standard {@link Canonicalizable#canonical node canonicalization} interface is used to
 116  * canonicalize nodes during decoding. Additionally, {@link IfNode branches} and
 117  * {@link IntegerSwitchNode switches} with constant conditions are simplified.
 118  */
 119 public abstract class PEGraphDecoder extends SimplifyingGraphDecoder {
 120 
 121     public static class Options {
 122         @Option(help = "Maximum inlining depth during partial evaluation before reporting an infinite recursion")//
 123         public static final OptionValue<Integer> InliningDepthError = new OptionValue<>(1000);
 124 
 125         @Option(help = "Max number of loop explosions per method.", type = OptionType.Debug)//
 126         public static final OptionValue<Integer> MaximumLoopExplosionCount = new OptionValue<>(10000);
 127 
 128         @Option(help = "Do not bail out but throw an exception on failed loop explosion.", type = OptionType.Debug) //
 129         public static final OptionValue<Boolean> FailedLoopExplosionIsFatal = new OptionValue<>(false);
 130     }
 131 
 132     protected class PEMethodScope extends MethodScope {
 133         /** The state of the caller method. Only non-null during method inlining. */
 134         protected final PEMethodScope caller;
 135         protected final ResolvedJavaMethod method;
 136         protected final InvokeData invokeData;
 137         protected final int inliningDepth;
 138 
 139         protected final LoopExplosionPlugin loopExplosionPlugin;
 140         protected final InvocationPlugins invocationPlugins;
 141         protected final InlineInvokePlugin[] inlineInvokePlugins;
 142         protected final ParameterPlugin parameterPlugin;
 143         protected final ValueNode[] arguments;
 144 
 145         protected FrameState outerState;
 146         protected FrameState exceptionState;
 147         protected ExceptionPlaceholderNode exceptionPlaceholderNode;
 148         protected NodeSourcePosition callerBytecodePosition;
 149 
 150         protected PEMethodScope(StructuredGraph targetGraph, PEMethodScope caller, LoopScope callerLoopScope, EncodedGraph encodedGraph, ResolvedJavaMethod method, InvokeData invokeData,
 151                         int inliningDepth, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins, ParameterPlugin parameterPlugin,
 152                         ValueNode[] arguments) {
 153             super(callerLoopScope, targetGraph, encodedGraph, loopExplosionKind(method, loopExplosionPlugin));
 154 
 155             this.caller = caller;
 156             this.method = method;
 157             this.invokeData = invokeData;
 158             this.inliningDepth = inliningDepth;
 159             this.loopExplosionPlugin = loopExplosionPlugin;
 160             this.invocationPlugins = invocationPlugins;
 161             this.inlineInvokePlugins = inlineInvokePlugins;
 162             this.parameterPlugin = parameterPlugin;
 163             this.arguments = arguments;
 164         }
 165 
 166         public boolean isInlinedMethod() {
 167             return caller != null;
 168         }
 169 
 170         public NodeSourcePosition getCallerBytecodePosition() {
 171             if (caller == null) {
 172                 return null;
 173             }
 174             if (callerBytecodePosition == null) {
 175                 JavaConstant constantReceiver = caller.invokeData == null ? null : caller.invokeData.constantReceiver;
 176                 NodeSourcePosition callerPosition = caller.getCallerBytecodePosition();
 177                 NodeSourcePosition invokePosition = invokeData.invoke.asNode().getNodeSourcePosition();
 178                 callerBytecodePosition = invokePosition != null ? invokePosition.addCaller(constantReceiver, callerPosition) : callerPosition;
 179             }
 180             return callerBytecodePosition;
 181         }
 182     }
 183 
 184     protected class PENonAppendGraphBuilderContext implements GraphBuilderContext {
 185         protected final PEMethodScope methodScope;
 186         protected final Invoke invoke;
 187 
 188         public PENonAppendGraphBuilderContext(PEMethodScope methodScope, Invoke invoke) {
 189             this.methodScope = methodScope;
 190             this.invoke = invoke;
 191         }
 192 
 193         @Override
 194         public BailoutException bailout(String string) {
 195             BailoutException bailout = new PermanentBailoutException(string);
 196             throw GraphUtil.createBailoutException(string, bailout, GraphUtil.approxSourceStackTraceElement(methodScope.getCallerBytecodePosition()));
 197         }
 198 
 199         @Override
 200         public StampProvider getStampProvider() {
 201             return stampProvider;
 202         }
 203 
 204         @Override
 205         public MetaAccessProvider getMetaAccess() {
 206             return metaAccess;
 207         }
 208 
 209         @Override
 210         public ConstantReflectionProvider getConstantReflection() {
 211             return constantReflection;
 212         }
 213 
 214         @Override
 215         public ConstantFieldProvider getConstantFieldProvider() {
 216             return constantFieldProvider;
 217         }
 218 
 219         @Override
 220         public StructuredGraph getGraph() {
 221             return methodScope.graph;
 222         }
 223 
 224         @Override
 225         public int getDepth() {
 226             return methodScope.inliningDepth;
 227         }
 228 
 229         @Override
 230         public IntrinsicContext getIntrinsic() {
 231             return null;
 232         }
 233 
 234         @Override
 235         public <T extends ValueNode> T append(T value) {
 236             throw unimplemented();
 237         }
 238 
 239         @Override
 240         public <T extends ValueNode> T recursiveAppend(T value) {
 241             throw unimplemented();
 242         }
 243 
 244         @Override
 245         public void push(JavaKind kind, ValueNode value) {
 246             throw unimplemented();
 247         }
 248 
 249         @Override
 250         public void handleReplacedInvoke(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, boolean inlineEverything) {
 251             throw unimplemented();
 252         }
 253 
 254         @Override
 255         public boolean intrinsify(BytecodeProvider bytecodeProvider, ResolvedJavaMethod targetMethod, ResolvedJavaMethod substitute, InvocationPlugin.Receiver receiver, ValueNode[] args) {
 256             return false;
 257         }
 258 
 259         @Override
 260         public void setStateAfter(StateSplit stateSplit) {
 261             throw unimplemented();
 262         }
 263 
 264         @Override
 265         public GraphBuilderContext getParent() {
 266             throw unimplemented();
 267         }
 268 
 269         @Override
 270         public Bytecode getCode() {
 271             throw unimplemented();
 272         }
 273 
 274         @Override
 275         public ResolvedJavaMethod getMethod() {
 276             throw unimplemented();
 277         }
 278 
 279         @Override
 280         public int bci() {
 281             return invoke.bci();
 282         }
 283 
 284         @Override
 285         public InvokeKind getInvokeKind() {
 286             throw unimplemented();
 287         }
 288 
 289         @Override
 290         public JavaType getInvokeReturnType() {
 291             throw unimplemented();
 292         }
 293     }
 294 
 295     protected class PEAppendGraphBuilderContext extends PENonAppendGraphBuilderContext {
 296         protected FixedWithNextNode lastInstr;
 297         protected ValueNode pushedNode;
 298 
 299         public PEAppendGraphBuilderContext(PEMethodScope inlineScope, FixedWithNextNode lastInstr) {
 300             super(inlineScope, inlineScope.invokeData.invoke);
 301             this.lastInstr = lastInstr;
 302         }
 303 
 304         @Override
 305         public void push(JavaKind kind, ValueNode value) {
 306             if (pushedNode != null) {
 307                 throw unimplemented("Only one push is supported");
 308             }
 309             pushedNode = value;
 310         }
 311 
 312         @Override
 313         public void setStateAfter(StateSplit stateSplit) {
 314             Node stateAfter = decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
 315             getGraph().add(stateAfter);
 316             FrameState fs = (FrameState) handleFloatingNodeAfterAdd(methodScope.caller, methodScope.callerLoopScope, stateAfter);
 317             stateSplit.setStateAfter(fs);
 318         }
 319 
 320         @SuppressWarnings("try")
 321         @Override
 322         public <T extends ValueNode> T append(T v) {
 323             if (v.graph() != null) {
 324                 return v;
 325             }
 326             try (DebugCloseable position = withNodeSoucePosition()) {
 327                 T added = getGraph().addOrUnique(v);
 328                 if (added == v) {
 329                     updateLastInstruction(v);
 330                 }
 331                 return added;
 332             }
 333         }
 334 
 335         private DebugCloseable withNodeSoucePosition() {
 336             if (getGraph().mayHaveNodeSourcePosition()) {
 337                 return getGraph().withNodeSourcePosition(methodScope.getCallerBytecodePosition());
 338             }
 339             return null;
 340         }
 341 
 342         @SuppressWarnings("try")
 343         @Override
 344         public <T extends ValueNode> T recursiveAppend(T v) {
 345             if (v.graph() != null) {
 346                 return v;
 347             }
 348             try (DebugCloseable position = withNodeSoucePosition()) {
 349                 T added = getGraph().addOrUniqueWithInputs(v);
 350                 if (added == v) {
 351                     updateLastInstruction(v);
 352                 }
 353                 return added;
 354             }
 355         }
 356 
 357         private <T extends ValueNode> void updateLastInstruction(T v) {
 358             if (v instanceof FixedNode) {
 359                 FixedNode fixedNode = (FixedNode) v;
 360                 lastInstr.setNext(fixedNode);
 361                 if (fixedNode instanceof FixedWithNextNode) {
 362                     FixedWithNextNode fixedWithNextNode = (FixedWithNextNode) fixedNode;
 363                     assert fixedWithNextNode.next() == null : "cannot append instruction to instruction which isn't end";
 364                     lastInstr = fixedWithNextNode;
 365                 } else {
 366                     lastInstr = null;
 367                 }
 368             }
 369         }
 370     }
 371 
 372     @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
 373     static class ExceptionPlaceholderNode extends ValueNode {
 374         public static final NodeClass<ExceptionPlaceholderNode> TYPE = NodeClass.create(ExceptionPlaceholderNode.class);
 375 
 376         protected ExceptionPlaceholderNode() {
 377             super(TYPE, StampFactory.object());
 378         }
 379     }
 380 
 381     public PEGraphDecoder(MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, ConstantFieldProvider constantFieldProvider, StampProvider stampProvider,
 382                     Architecture architecture) {
 383         super(metaAccess, constantReflection, constantFieldProvider, stampProvider, true, architecture);
 384     }
 385 
 386     protected static LoopExplosionKind loopExplosionKind(ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin) {
 387         if (loopExplosionPlugin == null) {
 388             return LoopExplosionKind.NONE;
 389         } else {
 390             return loopExplosionPlugin.loopExplosionKind(method);
 391         }
 392     }
 393 
 394     public void decode(StructuredGraph targetGraph, ResolvedJavaMethod method, LoopExplosionPlugin loopExplosionPlugin, InvocationPlugins invocationPlugins, InlineInvokePlugin[] inlineInvokePlugins,
 395                     ParameterPlugin parameterPlugin) {
 396         PEMethodScope methodScope = new PEMethodScope(targetGraph, null, null, lookupEncodedGraph(method, null), method, null, 0, loopExplosionPlugin, invocationPlugins, inlineInvokePlugins,
 397                         parameterPlugin, null);
 398         decode(createInitialLoopScope(methodScope, null));
 399         cleanupGraph(methodScope);
 400 
 401         Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After graph cleanup");
 402         assert methodScope.graph.verify();
 403 
 404         try {
 405             /* Check that the control flow graph can be computed, to catch problems early. */
 406             assert CFGVerifier.verify(ControlFlowGraph.compute(methodScope.graph, true, true, true, true));
 407         } catch (Throwable ex) {
 408             throw GraalError.shouldNotReachHere("Control flow graph not valid after partial evaluation");
 409         }
 410     }
 411 
 412     @Override
 413     protected void cleanupGraph(MethodScope methodScope) {
 414         super.cleanupGraph(methodScope);
 415 
 416         for (FrameState frameState : methodScope.graph.getNodes(FrameState.TYPE)) {
 417             if (frameState.bci == BytecodeFrame.UNWIND_BCI) {
 418                 /*
 419                  * handleMissingAfterExceptionFrameState is called during graph decoding from
 420                  * InliningUtil.processFrameState - but during graph decoding it does not do
 421                  * anything because the usages of the frameState are not available yet. So we need
 422                  * to call it again.
 423                  */
 424                 InliningUtil.handleMissingAfterExceptionFrameState(frameState);
 425 
 426                 /*
 427                  * The frameState must be gone now, because it is not a valid deoptimization point.
 428                  */
 429                 assert frameState.isDeleted();
 430             }
 431         }
 432     }
 433 
 434     @Override
 435     protected void checkLoopExplosionIteration(MethodScope s, LoopScope loopScope) {
 436         PEMethodScope methodScope = (PEMethodScope) s;
 437 
 438         if (loopScope.loopIteration > Options.MaximumLoopExplosionCount.getValue()) {
 439             throw tooManyLoopExplosionIterations(methodScope);
 440         }
 441     }
 442 
 443     private static RuntimeException tooManyLoopExplosionIterations(PEMethodScope methodScope) {
 444         String message = "too many loop explosion iterations - does the explosion not terminate for method " + methodScope.method + "?";
 445         RuntimeException bailout = Options.FailedLoopExplosionIsFatal.getValue() ? new RuntimeException(message) : new PermanentBailoutException(message);
 446         throw GraphUtil.createBailoutException(message, bailout, GraphUtil.approxSourceStackTraceElement(methodScope.getCallerBytecodePosition()));
 447     }
 448 
 449     @Override
 450     protected LoopScope handleInvoke(MethodScope s, LoopScope loopScope, InvokeData invokeData) {
 451         PEMethodScope methodScope = (PEMethodScope) s;
 452 
 453         /*
 454          * Decode the call target, but do not add it to the graph yet. This avoids adding usages for
 455          * all the arguments, which are expensive to remove again when we can inline the method.
 456          */
 457         assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke";
 458         CallTargetNode callTarget = (CallTargetNode) decodeFloatingNode(methodScope, loopScope, invokeData.callTargetOrderId);
 459         if (callTarget instanceof MethodCallTargetNode) {
 460             MethodCallTargetNode methodCall = (MethodCallTargetNode) callTarget;
 461             if (methodCall.invokeKind().hasReceiver()) {
 462                 invokeData.constantReceiver = methodCall.arguments().get(0).asJavaConstant();
 463             }
 464             LoopScope inlineLoopScope = trySimplifyInvoke(methodScope, loopScope, invokeData, (MethodCallTargetNode) callTarget);
 465             if (inlineLoopScope != null) {
 466                 return inlineLoopScope;
 467             }
 468         }
 469 
 470         /* We know that we need an invoke, so now we can add the call target to the graph. */
 471         methodScope.graph.add(callTarget);
 472         registerNode(loopScope, invokeData.callTargetOrderId, callTarget, false, false);
 473         return super.handleInvoke(methodScope, loopScope, invokeData);
 474     }
 475 
 476     protected LoopScope trySimplifyInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
 477         // attempt to devirtualize the call
 478         ResolvedJavaMethod specialCallTarget = MethodCallTargetNode.findSpecialCallTarget(callTarget.invokeKind(), callTarget.receiver(), callTarget.targetMethod(), invokeData.contextType);
 479         if (specialCallTarget != null) {
 480             callTarget.setTargetMethod(specialCallTarget);
 481             callTarget.setInvokeKind(InvokeKind.Special);
 482         }
 483 
 484         if (tryInvocationPlugin(methodScope, loopScope, invokeData, callTarget)) {
 485             /*
 486              * The invocation plugin handled the call, so decoding continues in the calling method.
 487              */
 488             return loopScope;
 489         }
 490         LoopScope inlineLoopScope = tryInline(methodScope, loopScope, invokeData, callTarget);
 491         if (inlineLoopScope != null) {
 492             /*
 493              * We can inline the call, so decoding continues in the inlined method.
 494              */
 495             return inlineLoopScope;
 496         }
 497 
 498         for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
 499             plugin.notifyNotInlined(new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke), callTarget.targetMethod(), invokeData.invoke);
 500         }
 501         return null;
 502     }
 503 
 504     protected boolean tryInvocationPlugin(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
 505         if (methodScope.invocationPlugins == null) {
 506             return false;
 507         }
 508 
 509         Invoke invoke = invokeData.invoke;
 510 
 511         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
 512         InvocationPlugin invocationPlugin = methodScope.invocationPlugins.lookupInvocation(targetMethod);
 513         if (invocationPlugin == null) {
 514             return false;
 515         }
 516 
 517         ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
 518         FixedWithNextNode invokePredecessor = (FixedWithNextNode) invoke.asNode().predecessor();
 519 
 520         /*
 521          * Remove invoke from graph so that invocation plugin can append nodes to the predecessor.
 522          */
 523         invoke.asNode().replaceAtPredecessor(null);
 524 
 525         PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, null, targetMethod, invokeData, methodScope.inliningDepth + 1, methodScope.loopExplosionPlugin,
 526                         methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments);
 527         PEAppendGraphBuilderContext graphBuilderContext = new PEAppendGraphBuilderContext(inlineScope, invokePredecessor);
 528         InvocationPluginReceiver invocationPluginReceiver = new InvocationPluginReceiver(graphBuilderContext);
 529 
 530         if (invocationPlugin.execute(graphBuilderContext, targetMethod, invocationPluginReceiver.init(targetMethod, arguments), arguments)) {
 531 
 532             if (graphBuilderContext.lastInstr != null) {
 533                 registerNode(loopScope, invokeData.invokeOrderId, graphBuilderContext.pushedNode, true, true);
 534                 invoke.asNode().replaceAtUsages(graphBuilderContext.pushedNode);
 535                 graphBuilderContext.lastInstr.setNext(nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(graphBuilderContext.lastInstr)));
 536             } else {
 537                 assert graphBuilderContext.pushedNode == null : "Why push a node when the invoke does not return anyway?";
 538                 invoke.asNode().replaceAtUsages(null);
 539             }
 540 
 541             deleteInvoke(invoke);
 542             return true;
 543 
 544         } else {
 545             /* Intrinsification failed, restore original state: invoke is in Graph. */
 546             invokePredecessor.setNext(invoke.asNode());
 547             return false;
 548         }
 549     }
 550 
 551     protected LoopScope tryInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, MethodCallTargetNode callTarget) {
 552         if (!callTarget.invokeKind().isDirect()) {
 553             return null;
 554         }
 555 
 556         ResolvedJavaMethod targetMethod = callTarget.targetMethod();
 557         if (!targetMethod.canBeInlined()) {
 558             return null;
 559         }
 560 
 561         ValueNode[] arguments = callTarget.arguments().toArray(new ValueNode[0]);
 562         GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, invokeData.invoke);
 563 
 564         for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
 565             InlineInfo inlineInfo = plugin.shouldInlineInvoke(graphBuilderContext, targetMethod, arguments);
 566             if (inlineInfo != null) {
 567                 if (inlineInfo.getMethodToInline() == null) {
 568                     return null;
 569                 } else {
 570                     return doInline(methodScope, loopScope, invokeData, inlineInfo, arguments);
 571                 }
 572             }
 573         }
 574         return null;
 575     }
 576 
 577     protected LoopScope doInline(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, InlineInfo inlineInfo, ValueNode[] arguments) {
 578         ResolvedJavaMethod inlineMethod = inlineInfo.getMethodToInline();
 579         EncodedGraph graphToInline = lookupEncodedGraph(inlineMethod, inlineInfo.getIntrinsicBytecodeProvider());
 580         if (graphToInline == null) {
 581             return null;
 582         }
 583 
 584         if (methodScope.inliningDepth > Options.InliningDepthError.getValue()) {
 585             throw tooDeepInlining(methodScope);
 586         }
 587 
 588         for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
 589             plugin.notifyBeforeInline(inlineMethod);
 590         }
 591 
 592         Invoke invoke = invokeData.invoke;
 593         FixedNode invokeNode = invoke.asNode();
 594         FixedWithNextNode predecessor = (FixedWithNextNode) invokeNode.predecessor();
 595         invokeNode.replaceAtPredecessor(null);
 596 
 597         PEMethodScope inlineScope = new PEMethodScope(methodScope.graph, methodScope, loopScope, graphToInline, inlineMethod, invokeData, methodScope.inliningDepth + 1,
 598                         methodScope.loopExplosionPlugin, methodScope.invocationPlugins, methodScope.inlineInvokePlugins, null, arguments);
 599 
 600         /*
 601          * After decoding all the nodes of the inlined method, we need to re-wire the return and
 602          * unwind nodes. Since inlining is non-recursive, this cannot be done at the end of this
 603          * method, but must be registered as a cleanup task that runs when all nodes of the inlined
 604          * methods have been decoded.
 605          */
 606         inlineScope.cleanupTasks.add(() -> finishInlining(methodScope, loopScope, invokeData, inlineMethod, inlineScope));
 607 
 608         /*
 609          * Do the actual inlining by returning the initial loop scope for the inlined method scope.
 610          */
 611         return createInitialLoopScope(inlineScope, predecessor);
 612     }
 613 
 614     protected void finishInlining(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, ResolvedJavaMethod inlineMethod, PEMethodScope inlineScope) {
 615         Invoke invoke = invokeData.invoke;
 616         FixedNode invokeNode = invoke.asNode();
 617 
 618         ValueNode exceptionValue = null;
 619         List<UnwindNode> unwindNodes = inlineScope.unwindNodes;
 620         Iterator<UnwindNode> iter = unwindNodes.iterator();
 621         while (iter.hasNext()) {
 622             if (iter.next().isDeleted()) {
 623                 iter.remove();
 624             }
 625         }
 626 
 627         if (!unwindNodes.isEmpty()) {
 628             FixedNode unwindReplacement;
 629             if (invoke instanceof InvokeWithExceptionNode) {
 630                 /* Decoding continues for the exception handler. */
 631                 unwindReplacement = makeStubNode(methodScope, loopScope, invokeData.exceptionNextOrderId);
 632             } else {
 633                 /* No exception handler available, so the only thing we can do is deoptimize. */
 634                 unwindReplacement = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.NotCompiledExceptionHandler));
 635             }
 636 
 637             if (unwindNodes.size() == 1) {
 638                 /* Only one UnwindNode, we can use the exception directly. */
 639                 UnwindNode unwindNode = unwindNodes.get(0);
 640                 exceptionValue = unwindNode.exception();
 641                 unwindNode.replaceAndDelete(unwindReplacement);
 642 
 643             } else {
 644                 /*
 645                  * More than one UnwindNode. This can happen with the loop explosion strategy
 646                  * FULL_EXPLODE_UNTIL_RETURN, where we keep exploding after the loop and therefore
 647                  * also explode exception paths. Merge the exception in a similar way as multiple
 648                  * return values.
 649                  */
 650                 MergeNode unwindMergeNode = methodScope.graph.add(new MergeNode());
 651                 exceptionValue = InliningUtil.mergeValueProducers(unwindMergeNode, unwindNodes, null, unwindNode -> unwindNode.exception());
 652                 unwindMergeNode.setNext(unwindReplacement);
 653 
 654                 ensureExceptionStateDecoded(inlineScope);
 655                 unwindMergeNode.setStateAfter(inlineScope.exceptionState.duplicateModified(JavaKind.Object, JavaKind.Object, exceptionValue));
 656             }
 657         }
 658 
 659         assert invoke.next() == null;
 660         assert !(invoke instanceof InvokeWithExceptionNode) || ((InvokeWithExceptionNode) invoke).exceptionEdge() == null;
 661 
 662         ValueNode returnValue;
 663         List<ReturnNode> returnNodes = inlineScope.returnNodes;
 664         if (!returnNodes.isEmpty()) {
 665             if (returnNodes.size() == 1) {
 666                 ReturnNode returnNode = returnNodes.get(0);
 667                 returnValue = returnNode.result();
 668                 FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, AbstractBeginNode.prevBegin(returnNode));
 669                 returnNode.replaceAndDelete(n);
 670             } else {
 671                 AbstractMergeNode merge = methodScope.graph.add(new MergeNode());
 672                 merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
 673                 returnValue = InliningUtil.mergeReturns(merge, returnNodes, null);
 674                 FixedNode n = nodeAfterInvoke(methodScope, loopScope, invokeData, merge);
 675                 merge.setNext(n);
 676             }
 677         } else {
 678             returnValue = null;
 679         }
 680         invokeNode.replaceAtUsages(returnValue);
 681 
 682         /*
 683          * Usage the handles that we have on the return value and the exception to update the
 684          * orderId->Node table.
 685          */
 686         registerNode(loopScope, invokeData.invokeOrderId, returnValue, true, true);
 687         if (invoke instanceof InvokeWithExceptionNode) {
 688             registerNode(loopScope, invokeData.exceptionOrderId, exceptionValue, true, true);
 689         }
 690         if (inlineScope.exceptionPlaceholderNode != null) {
 691             inlineScope.exceptionPlaceholderNode.replaceAtUsagesAndDelete(exceptionValue);
 692         }
 693         deleteInvoke(invoke);
 694 
 695         for (InlineInvokePlugin plugin : methodScope.inlineInvokePlugins) {
 696             plugin.notifyAfterInline(inlineMethod);
 697         }
 698 
 699         if (Debug.isDumpEnabled(Debug.INFO_LOG_LEVEL) && DumpDuringGraphBuilding.getValue()) {
 700             Debug.dump(Debug.INFO_LOG_LEVEL, methodScope.graph, "Inline finished: %s.%s", inlineMethod.getDeclaringClass().getUnqualifiedName(), inlineMethod.getName());
 701         }
 702     }
 703 
 704     private static RuntimeException tooDeepInlining(PEMethodScope methodScope) {
 705         HashMap<ResolvedJavaMethod, Integer> methodCounts = new HashMap<>();
 706         for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) {
 707             Integer oldCount = methodCounts.get(cur.method);
 708             methodCounts.put(cur.method, oldCount == null ? 1 : oldCount + 1);
 709         }
 710 
 711         List<Map.Entry<ResolvedJavaMethod, Integer>> methods = new ArrayList<>(methodCounts.entrySet());
 712         methods.sort((e1, e2) -> -Integer.compare(e1.getValue(), e2.getValue()));
 713 
 714         StringBuilder msg = new StringBuilder("Too deep inlining, probably caused by recursive inlining.").append(System.lineSeparator()).append("== Inlined methods ordered by inlining frequency:");
 715         for (Map.Entry<ResolvedJavaMethod, Integer> entry : methods) {
 716             msg.append(System.lineSeparator()).append(entry.getKey().format("%H.%n(%p) [")).append(entry.getValue()).append("]");
 717         }
 718         msg.append(System.lineSeparator()).append("== Complete stack trace of inlined methods:");
 719         int lastBci = 0;
 720         for (PEMethodScope cur = methodScope; cur != null; cur = cur.caller) {
 721             msg.append(System.lineSeparator()).append(cur.method.asStackTraceElement(lastBci));
 722             if (cur.invokeData != null) {
 723                 lastBci = cur.invokeData.invoke.bci();
 724             } else {
 725                 lastBci = 0;
 726             }
 727         }
 728 
 729         throw new PermanentBailoutException(msg.toString());
 730     }
 731 
 732     public FixedNode nodeAfterInvoke(PEMethodScope methodScope, LoopScope loopScope, InvokeData invokeData, AbstractBeginNode lastBlock) {
 733         assert lastBlock.isAlive();
 734         FixedNode n;
 735         if (invokeData.invoke instanceof InvokeWithExceptionNode) {
 736             registerNode(loopScope, invokeData.nextOrderId, lastBlock, false, false);
 737             n = makeStubNode(methodScope, loopScope, invokeData.nextNextOrderId);
 738         } else {
 739             n = makeStubNode(methodScope, loopScope, invokeData.nextOrderId);
 740         }
 741         return n;
 742     }
 743 
 744     private static void deleteInvoke(Invoke invoke) {
 745         /*
 746          * Clean up unused nodes. We cannot just call killCFG on the invoke node because that can
 747          * kill too much: nodes that are decoded later can use values that appear unused by now.
 748          */
 749         FrameState frameState = invoke.stateAfter();
 750         invoke.asNode().safeDelete();
 751         assert invoke.callTarget() == null : "must not have been added to the graph yet";
 752         if (frameState != null && frameState.hasNoUsages()) {
 753             frameState.safeDelete();
 754         }
 755     }
 756 
 757     protected abstract EncodedGraph lookupEncodedGraph(ResolvedJavaMethod method, BytecodeProvider intrinsicBytecodeProvider);
 758 
 759     @SuppressWarnings("try")
 760     @Override
 761     protected void handleFixedNode(MethodScope s, LoopScope loopScope, int nodeOrderId, FixedNode node) {
 762         PEMethodScope methodScope = (PEMethodScope) s;
 763         if (node instanceof ForeignCallNode) {
 764             ForeignCallNode foreignCall = (ForeignCallNode) node;
 765             if (foreignCall.getBci() == BytecodeFrame.UNKNOWN_BCI && methodScope.invokeData != null) {
 766                 foreignCall.setBci(methodScope.invokeData.invoke.bci());
 767             }
 768         }
 769 
 770         NodeSourcePosition pos = node.getNodeSourcePosition();
 771         if (pos != null && methodScope.isInlinedMethod()) {
 772             NodeSourcePosition newPosition = pos.addCaller(methodScope.getCallerBytecodePosition());
 773             try (DebugCloseable scope = node.graph().withoutNodeSourcePosition()) {
 774                 super.handleFixedNode(s, loopScope, nodeOrderId, node);
 775             }
 776             if (node.isAlive()) {
 777                 node.setNodeSourcePosition(newPosition);
 778             }
 779         } else {
 780             super.handleFixedNode(s, loopScope, nodeOrderId, node);
 781         }
 782 
 783     }
 784 
 785     @Override
 786     protected Node handleFloatingNodeBeforeAdd(MethodScope s, LoopScope loopScope, Node node) {
 787         PEMethodScope methodScope = (PEMethodScope) s;
 788 
 789         if (node instanceof ParameterNode) {
 790             ParameterNode param = (ParameterNode) node;
 791             if (methodScope.arguments != null) {
 792                 Node result = methodScope.arguments[param.index()];
 793                 assert result != null;
 794                 return result;
 795 
 796             } else if (methodScope.parameterPlugin != null) {
 797                 GraphBuilderContext graphBuilderContext = new PENonAppendGraphBuilderContext(methodScope, null);
 798                 Node result = methodScope.parameterPlugin.interceptParameter(graphBuilderContext, param.index(),
 799                                 StampPair.create(param.stamp(), param.uncheckedStamp()));
 800                 if (result != null) {
 801                     return result;
 802                 }
 803             }
 804 
 805         }
 806 
 807         return super.handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
 808     }
 809 
 810     protected void ensureOuterStateDecoded(PEMethodScope methodScope) {
 811         if (methodScope.outerState == null && methodScope.caller != null) {
 812             FrameState stateAtReturn = methodScope.invokeData.invoke.stateAfter();
 813             if (stateAtReturn == null) {
 814                 stateAtReturn = (FrameState) decodeFloatingNode(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId);
 815             }
 816 
 817             JavaKind invokeReturnKind = methodScope.invokeData.invoke.asNode().getStackKind();
 818             FrameState outerState = stateAtReturn.duplicateModified(methodScope.graph, methodScope.invokeData.invoke.bci(), stateAtReturn.rethrowException(), true, invokeReturnKind, null, null);
 819 
 820             /*
 821              * When the encoded graph has methods inlining, we can already have a proper caller
 822              * state. If not, we set the caller state here.
 823              */
 824             if (outerState.outerFrameState() == null && methodScope.caller != null) {
 825                 ensureOuterStateDecoded(methodScope.caller);
 826                 outerState.setOuterFrameState(methodScope.caller.outerState);
 827             }
 828             methodScope.outerState = outerState;
 829         }
 830     }
 831 
 832     protected void ensureStateAfterDecoded(PEMethodScope methodScope) {
 833         if (methodScope.invokeData.invoke.stateAfter() == null) {
 834             methodScope.invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.stateAfterOrderId));
 835         }
 836     }
 837 
 838     protected void ensureExceptionStateDecoded(PEMethodScope methodScope) {
 839         if (methodScope.exceptionState == null && methodScope.caller != null && methodScope.invokeData.invoke instanceof InvokeWithExceptionNode) {
 840             ensureStateAfterDecoded(methodScope);
 841 
 842             assert methodScope.exceptionPlaceholderNode == null;
 843             methodScope.exceptionPlaceholderNode = methodScope.graph.add(new ExceptionPlaceholderNode());
 844             registerNode(methodScope.callerLoopScope, methodScope.invokeData.exceptionOrderId, methodScope.exceptionPlaceholderNode, false, false);
 845             FrameState exceptionState = (FrameState) ensureNodeCreated(methodScope.caller, methodScope.callerLoopScope, methodScope.invokeData.exceptionStateOrderId);
 846 
 847             if (exceptionState.outerFrameState() == null && methodScope.caller != null) {
 848                 ensureOuterStateDecoded(methodScope.caller);
 849                 exceptionState.setOuterFrameState(methodScope.caller.outerState);
 850             }
 851             methodScope.exceptionState = exceptionState;
 852         }
 853     }
 854 
 855     @Override
 856     protected Node addFloatingNode(MethodScope s, Node node) {
 857         Node addedNode = super.addFloatingNode(s, node);
 858         PEMethodScope methodScope = (PEMethodScope) s;
 859         NodeSourcePosition pos = node.getNodeSourcePosition();
 860         if (methodScope.isInlinedMethod()) {
 861             if (pos != null) {
 862                 NodeSourcePosition bytecodePosition = methodScope.getCallerBytecodePosition();
 863                 node.setNodeSourcePosition(pos.addCaller(bytecodePosition));
 864             }
 865         }
 866         return addedNode;
 867     }
 868 
 869     @Override
 870     protected Node handleFloatingNodeAfterAdd(MethodScope s, LoopScope loopScope, Node node) {
 871         PEMethodScope methodScope = (PEMethodScope) s;
 872 
 873         if (methodScope.isInlinedMethod()) {
 874             if (node instanceof FrameState) {
 875                 FrameState frameState = (FrameState) node;
 876 
 877                 ensureOuterStateDecoded(methodScope);
 878                 if (frameState.bci < 0) {
 879                     ensureExceptionStateDecoded(methodScope);
 880                 }
 881                 List<ValueNode> invokeArgsList = null;
 882                 if (frameState.bci == BytecodeFrame.BEFORE_BCI) {
 883                     /*
 884                      * We know that the argument list is only used in this case, so avoid the List
 885                      * allocation for "normal" bcis.
 886                      */
 887                     invokeArgsList = Arrays.asList(methodScope.arguments);
 888                 }
 889                 return InliningUtil.processFrameState(frameState, methodScope.invokeData.invoke, methodScope.method, methodScope.exceptionState, methodScope.outerState, true, methodScope.method,
 890                                 invokeArgsList);
 891 
 892             } else if (node instanceof MonitorIdNode) {
 893                 ensureOuterStateDecoded(methodScope);
 894                 InliningUtil.processMonitorId(methodScope.outerState, (MonitorIdNode) node);
 895                 return node;
 896             }
 897         }
 898 
 899         return node;
 900     }
 901 }