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