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