1 /* 2 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 package org.graalvm.compiler.nodes; 26 27 import static org.graalvm.compiler.debug.GraalError.shouldNotReachHere; 28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED; 29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED; 30 31 import java.util.ArrayDeque; 32 import java.util.ArrayList; 33 import java.util.Arrays; 34 import java.util.BitSet; 35 import java.util.Deque; 36 import java.util.Iterator; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.SortedMap; 40 import java.util.TreeMap; 41 42 import jdk.internal.vm.compiler.collections.EconomicMap; 43 import jdk.internal.vm.compiler.collections.EconomicSet; 44 import jdk.internal.vm.compiler.collections.Equivalence; 45 import org.graalvm.compiler.core.common.Fields; 46 import org.graalvm.compiler.core.common.PermanentBailoutException; 47 import org.graalvm.compiler.core.common.util.TypeReader; 48 import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader; 49 import org.graalvm.compiler.debug.DebugContext; 50 import org.graalvm.compiler.debug.GraalError; 51 import org.graalvm.compiler.graph.Edges; 52 import org.graalvm.compiler.graph.Graph; 53 import org.graalvm.compiler.graph.Node; 54 import org.graalvm.compiler.graph.NodeBitMap; 55 import org.graalvm.compiler.graph.NodeClass; 56 import org.graalvm.compiler.graph.NodeInputList; 57 import org.graalvm.compiler.graph.NodeList; 58 import org.graalvm.compiler.graph.NodeSourcePosition; 59 import org.graalvm.compiler.graph.NodeSuccessorList; 60 import org.graalvm.compiler.graph.spi.Canonicalizable; 61 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 62 import org.graalvm.compiler.nodeinfo.InputType; 63 import org.graalvm.compiler.nodeinfo.NodeInfo; 64 import org.graalvm.compiler.nodes.GraphDecoder.MethodScope; 65 import org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder; 66 import org.graalvm.compiler.nodes.calc.FloatingNode; 67 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode; 68 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind; 69 import org.graalvm.compiler.options.OptionValues; 70 71 import jdk.vm.ci.code.Architecture; 72 import jdk.vm.ci.meta.DeoptimizationAction; 73 import jdk.vm.ci.meta.DeoptimizationReason; 74 import jdk.vm.ci.meta.JavaConstant; 75 import jdk.vm.ci.meta.JavaKind; 76 import jdk.vm.ci.meta.PrimitiveConstant; 77 import jdk.vm.ci.meta.ResolvedJavaType; 78 79 /** 80 * Decoder for {@link EncodedGraph encoded graphs} produced by {@link GraphEncoder}. Support for 81 * loop explosion during decoding is built into this class, because it requires many interactions 82 * with the decoding process. Subclasses can provide canonicalization and simplification of nodes 83 * during decoding, as well as method inlining during decoding. 84 */ 85 public class GraphDecoder { 86 87 /** Decoding state maintained for each encoded graph. */ 88 protected class MethodScope { 89 /** The loop that contains the call. Only non-null during method inlining. */ 90 public final LoopScope callerLoopScope; 91 /** 92 * Mark for nodes that were present before the decoding of this method started. Note that 93 * nodes that were decoded after the mark can still be part of an outer method, since 94 * floating nodes of outer methods are decoded lazily. 95 */ 96 public final Graph.Mark methodStartMark; 97 /** The encode graph that is decoded. */ 98 public final EncodedGraph encodedGraph; 99 /** The highest node order id that a fixed node has in the EncodedGraph. */ 100 public final int maxFixedNodeOrderId; 101 /** Access to the encoded graph. */ 102 public final TypeReader reader; 103 /** The kind of loop explosion to be performed during decoding. */ 104 public final LoopExplosionKind loopExplosion; 105 106 /** All return nodes encountered during decoding. */ 107 public final List<ControlSinkNode> returnAndUnwindNodes; 108 109 /** All merges created during loop explosion. */ 110 public final EconomicSet<Node> loopExplosionMerges; 111 112 /** 113 * The start of explosion, and the merge point for when irreducible loops are detected. Only 114 * used when {@link MethodScope#loopExplosion} is {@link LoopExplosionKind#MERGE_EXPLODE}. 115 */ 116 public MergeNode loopExplosionHead; 117 118 protected MethodScope(LoopScope callerLoopScope, StructuredGraph graph, EncodedGraph encodedGraph, LoopExplosionKind loopExplosion) { 119 this.callerLoopScope = callerLoopScope; 120 this.methodStartMark = graph.getMark(); 121 this.encodedGraph = encodedGraph; 122 this.loopExplosion = loopExplosion; 123 this.returnAndUnwindNodes = new ArrayList<>(2); 124 125 if (encodedGraph != null) { 126 reader = UnsafeArrayTypeReader.create(encodedGraph.getEncoding(), encodedGraph.getStartOffset(), architecture.supportsUnalignedMemoryAccess()); 127 maxFixedNodeOrderId = reader.getUVInt(); 128 if (encodedGraph.nodeStartOffsets == null) { 129 int nodeCount = reader.getUVInt(); 130 int[] nodeStartOffsets = new int[nodeCount]; 131 for (int i = 0; i < nodeCount; i++) { 132 nodeStartOffsets[i] = encodedGraph.getStartOffset() - reader.getUVInt(); 133 } 134 encodedGraph.nodeStartOffsets = nodeStartOffsets; 135 graph.setGuardsStage((StructuredGraph.GuardsStage) readObject(this)); 136 } 137 } else { 138 reader = null; 139 maxFixedNodeOrderId = 0; 140 } 141 142 if (loopExplosion != LoopExplosionKind.NONE) { 143 loopExplosionMerges = EconomicSet.create(Equivalence.IDENTITY); 144 } else { 145 loopExplosionMerges = null; 146 } 147 } 148 149 public boolean isInlinedMethod() { 150 return false; 151 } 152 153 public NodeSourcePosition getCallerBytecodePosition() { 154 return getCallerBytecodePosition(null); 155 } 156 157 public NodeSourcePosition getCallerBytecodePosition(NodeSourcePosition position) { 158 return position; 159 } 160 161 } 162 163 /** Decoding state maintained for each loop in the encoded graph. */ 164 protected static class LoopScope { 165 public final MethodScope methodScope; 166 public final LoopScope outer; 167 public final int loopDepth; 168 public final int loopIteration; 169 /** 170 * Upcoming loop iterations during loop explosions that have not been processed yet. Only 171 * used when {@link MethodScope#loopExplosion} is not {@link LoopExplosionKind#NONE}. 172 */ 173 public Deque<LoopScope> nextIterations; 174 /** 175 * Information about already processed loop iterations for state merging during loop 176 * explosion. Only used when {@link MethodScope#loopExplosion} is 177 * {@link LoopExplosionKind#MERGE_EXPLODE}. 178 */ 179 public final EconomicMap<LoopExplosionState, LoopExplosionState> iterationStates; 180 public final int loopBeginOrderId; 181 /** 182 * The worklist of fixed nodes to process. Since we already the correct processing order 183 * from the orderId, we just set the orderId bit in the bitset when a node is ready for 184 * processing. The lowest set bit is the next node to process. 185 */ 186 public final BitSet nodesToProcess; 187 /** Nodes that have been created, indexed by the orderId. */ 188 public final Node[] createdNodes; 189 /** 190 * Nodes that have been created in outer loop scopes and existed before starting to process 191 * this loop, indexed by the orderId. Only used when {@link MethodScope#loopExplosion} is 192 * not {@link LoopExplosionKind#NONE}. 193 */ 194 public final Node[] initialCreatedNodes; 195 196 protected LoopScope(MethodScope methodScope) { 197 this.methodScope = methodScope; 198 this.outer = null; 199 this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>(2) : null; 200 this.loopDepth = 0; 201 this.loopIteration = 0; 202 this.iterationStates = null; 203 this.loopBeginOrderId = -1; 204 205 int nodeCount = methodScope.encodedGraph.nodeStartOffsets.length; 206 this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId); 207 this.createdNodes = new Node[nodeCount]; 208 this.initialCreatedNodes = null; 209 } 210 211 protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, Node[] initialCreatedNodes, Node[] createdNodes, 212 Deque<LoopScope> nextIterations, EconomicMap<LoopExplosionState, LoopExplosionState> iterationStates) { 213 this.methodScope = methodScope; 214 this.outer = outer; 215 this.loopDepth = loopDepth; 216 this.loopIteration = loopIteration; 217 this.nextIterations = nextIterations; 218 this.iterationStates = iterationStates; 219 this.loopBeginOrderId = loopBeginOrderId; 220 this.nodesToProcess = new BitSet(methodScope.maxFixedNodeOrderId); 221 this.initialCreatedNodes = initialCreatedNodes; 222 this.createdNodes = createdNodes; 223 } 224 225 @Override 226 public String toString() { 227 return loopDepth + "," + loopIteration + (loopBeginOrderId == -1 ? "" : "#" + loopBeginOrderId); 228 } 229 } 230 231 protected static class LoopExplosionState { 232 public final FrameState state; 233 public final MergeNode merge; 234 public final int hashCode; 235 236 protected LoopExplosionState(FrameState state, MergeNode merge) { 237 this.state = state; 238 this.merge = merge; 239 240 int h = 0; 241 for (ValueNode value : state.values()) { 242 if (value == null) { 243 h = h * 31 + 1234; 244 } else { 245 h = h * 31 + ProxyPlaceholder.unwrap(value).hashCode(); 246 } 247 } 248 this.hashCode = h; 249 } 250 251 @Override 252 public boolean equals(Object obj) { 253 if (!(obj instanceof LoopExplosionState)) { 254 return false; 255 } 256 257 FrameState otherState = ((LoopExplosionState) obj).state; 258 FrameState thisState = state; 259 assert thisState.outerFrameState() == otherState.outerFrameState(); 260 261 Iterator<ValueNode> thisIter = thisState.values().iterator(); 262 Iterator<ValueNode> otherIter = otherState.values().iterator(); 263 while (thisIter.hasNext() && otherIter.hasNext()) { 264 ValueNode thisValue = ProxyPlaceholder.unwrap(thisIter.next()); 265 ValueNode otherValue = ProxyPlaceholder.unwrap(otherIter.next()); 266 if (thisValue != otherValue) { 267 return false; 268 } 269 } 270 return thisIter.hasNext() == otherIter.hasNext(); 271 } 272 273 @Override 274 public int hashCode() { 275 return hashCode; 276 } 277 } 278 279 /** 280 * Additional information encoded for {@link Invoke} nodes to allow method inlining without 281 * decoding the frame state and successors beforehand. 282 */ 283 protected static class InvokeData { 284 public final Invoke invoke; 285 public final ResolvedJavaType contextType; 286 public final int invokeOrderId; 287 public final int callTargetOrderId; 288 public final int stateAfterOrderId; 289 public final int nextOrderId; 290 291 public final int nextNextOrderId; 292 public final int exceptionOrderId; 293 public final int exceptionStateOrderId; 294 public final int exceptionNextOrderId; 295 public JavaConstant constantReceiver; 296 297 protected InvokeData(Invoke invoke, ResolvedJavaType contextType, int invokeOrderId, int callTargetOrderId, int stateAfterOrderId, int nextOrderId, int nextNextOrderId, int exceptionOrderId, 298 int exceptionStateOrderId, int exceptionNextOrderId) { 299 this.invoke = invoke; 300 this.contextType = contextType; 301 this.invokeOrderId = invokeOrderId; 302 this.callTargetOrderId = callTargetOrderId; 303 this.stateAfterOrderId = stateAfterOrderId; 304 this.nextOrderId = nextOrderId; 305 this.nextNextOrderId = nextNextOrderId; 306 this.exceptionOrderId = exceptionOrderId; 307 this.exceptionStateOrderId = exceptionStateOrderId; 308 this.exceptionNextOrderId = exceptionNextOrderId; 309 } 310 } 311 312 /** 313 * A node that is created during {@link LoopExplosionKind#MERGE_EXPLODE loop explosion} that can 314 * later be replaced by a ProxyNode if {@link LoopDetector loop detection} finds out that the 315 * value is defined in the loop, but used outside the loop. 316 */ 317 @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED) 318 protected static final class ProxyPlaceholder extends FloatingNode implements Canonicalizable { 319 public static final NodeClass<ProxyPlaceholder> TYPE = NodeClass.create(ProxyPlaceholder.class); 320 321 @Input ValueNode value; 322 @Input(InputType.Unchecked) Node proxyPoint; 323 324 public ProxyPlaceholder(ValueNode value, MergeNode proxyPoint) { 325 super(TYPE, value.stamp(NodeView.DEFAULT)); 326 this.value = value; 327 this.proxyPoint = proxyPoint; 328 } 329 330 void setValue(ValueNode value) { 331 updateUsages(this.value, value); 332 this.value = value; 333 } 334 335 @Override 336 public Node canonical(CanonicalizerTool tool) { 337 if (tool.allUsagesAvailable()) { 338 /* The node is always unnecessary after graph decoding. */ 339 return value; 340 } else { 341 return this; 342 } 343 } 344 345 public static ValueNode unwrap(ValueNode value) { 346 ValueNode result = value; 347 while (result instanceof ProxyPlaceholder) { 348 result = ((ProxyPlaceholder) result).value; 349 } 350 return result; 351 } 352 } 353 354 protected final Architecture architecture; 355 /** The target graph where decoded nodes are added to. */ 356 protected final StructuredGraph graph; 357 protected final OptionValues options; 358 protected final DebugContext debug; 359 360 private final EconomicMap<NodeClass<?>, ArrayDeque<Node>> reusableFloatingNodes; 361 362 public GraphDecoder(Architecture architecture, StructuredGraph graph) { 363 this.architecture = architecture; 364 this.graph = graph; 365 this.options = graph.getOptions(); 366 this.debug = graph.getDebug(); 367 reusableFloatingNodes = EconomicMap.create(Equivalence.IDENTITY); 368 } 369 370 @SuppressWarnings("try") 371 public final void decode(EncodedGraph encodedGraph) { 372 try (DebugContext.Scope scope = debug.scope("GraphDecoder", graph)) { 373 MethodScope methodScope = new MethodScope(null, graph, encodedGraph, LoopExplosionKind.NONE); 374 decode(createInitialLoopScope(methodScope, null)); 375 cleanupGraph(methodScope); 376 assert graph.verify(); 377 } catch (Throwable ex) { 378 debug.handle(ex); 379 } 380 } 381 382 protected final LoopScope createInitialLoopScope(MethodScope methodScope, FixedWithNextNode startNode) { 383 LoopScope loopScope = new LoopScope(methodScope); 384 FixedNode firstNode; 385 if (startNode != null) { 386 /* 387 * The start node of a graph can be referenced as the guard for a GuardedNode. We 388 * register the previous block node, so that such guards are correctly anchored when 389 * doing inlining during graph decoding. 390 */ 391 registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, AbstractBeginNode.prevBegin(startNode), false, false); 392 393 firstNode = makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID); 394 startNode.setNext(firstNode); 395 loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID); 396 } else { 397 firstNode = graph.start(); 398 registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, firstNode, false, false); 399 loopScope.nodesToProcess.set(GraphEncoder.START_NODE_ORDER_ID); 400 } 401 return loopScope; 402 } 403 404 protected final void decode(LoopScope initialLoopScope) { 405 LoopScope loopScope = initialLoopScope; 406 /* Process (inlined) methods. */ 407 while (loopScope != null) { 408 MethodScope methodScope = loopScope.methodScope; 409 410 /* Process loops of method. */ 411 while (loopScope != null) { 412 413 /* Process nodes of loop. */ 414 while (!loopScope.nodesToProcess.isEmpty()) { 415 loopScope = processNextNode(methodScope, loopScope); 416 methodScope = loopScope.methodScope; 417 /* 418 * We can have entered a new loop, and we can have entered a new inlined method. 419 */ 420 } 421 422 /* Finished with a loop. */ 423 if (loopScope.nextIterations != null && !loopScope.nextIterations.isEmpty()) { 424 /* Loop explosion: process the loop iteration. */ 425 assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1; 426 loopScope = loopScope.nextIterations.removeFirst(); 427 } else { 428 propagateCreatedNodes(loopScope); 429 loopScope = loopScope.outer; 430 } 431 } 432 433 /* 434 * Finished with an inlined method. Perform end-of-method cleanup tasks. 435 */ 436 if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { 437 LoopDetector loopDetector = new LoopDetector(graph, methodScope); 438 loopDetector.run(); 439 } 440 if (methodScope.isInlinedMethod()) { 441 finishInlining(methodScope); 442 } 443 444 /* continue with the caller */ 445 loopScope = methodScope.callerLoopScope; 446 } 447 } 448 449 protected void finishInlining(@SuppressWarnings("unused") MethodScope inlineScope) { 450 } 451 452 private static void propagateCreatedNodes(LoopScope loopScope) { 453 if (loopScope.outer == null || loopScope.createdNodes != loopScope.outer.createdNodes) { 454 return; 455 } 456 457 /* Register nodes that were created while decoding the loop to the outside scope. */ 458 for (int i = 0; i < loopScope.createdNodes.length; i++) { 459 if (loopScope.outer.createdNodes[i] == null) { 460 loopScope.outer.createdNodes[i] = loopScope.createdNodes[i]; 461 } 462 } 463 } 464 465 protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) { 466 int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0); 467 loopScope.nodesToProcess.clear(nodeOrderId); 468 469 FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId); 470 if (node.isDeleted()) { 471 return loopScope; 472 } 473 474 if ((node instanceof MergeNode || 475 (node instanceof LoopBeginNode && (methodScope.loopExplosion == LoopExplosionKind.FULL_UNROLL || methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE || 476 methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN))) && 477 ((AbstractMergeNode) node).forwardEndCount() == 1) { 478 AbstractMergeNode merge = (AbstractMergeNode) node; 479 EndNode singleEnd = merge.forwardEndAt(0); 480 481 /* Nodes that would use this merge as the guard need to use the previous block. */ 482 registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false); 483 484 FixedNode next = makeStubNode(methodScope, loopScope, nodeOrderId + GraphEncoder.BEGIN_NEXT_ORDER_ID_OFFSET); 485 singleEnd.replaceAtPredecessor(next); 486 487 merge.safeDelete(); 488 singleEnd.safeDelete(); 489 return loopScope; 490 } 491 492 LoopScope successorAddScope = loopScope; 493 boolean updatePredecessors = true; 494 if (node instanceof LoopExitNode) { 495 if (methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN || (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth > 1)) { 496 /* 497 * We do not want to merge loop exits of inner loops. Instead, we want to keep 498 * exploding the outer loop separately for every loop exit and then merge the outer 499 * loop. Therefore, we create a new LoopScope of the outer loop for every loop exit 500 * of the inner loop. 501 */ 502 LoopScope outerScope = loopScope.outer; 503 int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1; 504 successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, 505 outerScope.initialCreatedNodes == null ? null : Arrays.copyOf(outerScope.initialCreatedNodes, outerScope.initialCreatedNodes.length), 506 Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), outerScope.nextIterations, outerScope.iterationStates); 507 checkLoopExplosionIteration(methodScope, successorAddScope); 508 509 /* 510 * Nodes that are still unprocessed in the outer scope might be merge nodes that are 511 * also reachable from the new exploded scope. Clearing them ensures that we do not 512 * merge, but instead keep exploding. 513 */ 514 for (int id = outerScope.nodesToProcess.nextSetBit(0); id >= 0; id = outerScope.nodesToProcess.nextSetBit(id + 1)) { 515 successorAddScope.createdNodes[id] = null; 516 } 517 518 outerScope.nextIterations.addLast(successorAddScope); 519 } else { 520 successorAddScope = loopScope.outer; 521 } 522 updatePredecessors = methodScope.loopExplosion == LoopExplosionKind.NONE; 523 } 524 525 methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); 526 int typeId = methodScope.reader.getUVInt(); 527 assert node.getNodeClass() == methodScope.encodedGraph.getNodeClasses()[typeId]; 528 makeFixedNodeInputs(methodScope, loopScope, node); 529 readProperties(methodScope, node); 530 makeSuccessorStubs(methodScope, successorAddScope, node, updatePredecessors); 531 532 LoopScope resultScope = loopScope; 533 if (node instanceof LoopBeginNode) { 534 if (methodScope.loopExplosion != LoopExplosionKind.NONE) { 535 handleLoopExplosionBegin(methodScope, loopScope, (LoopBeginNode) node); 536 } 537 538 } else if (node instanceof LoopExitNode) { 539 if (methodScope.loopExplosion != LoopExplosionKind.NONE) { 540 handleLoopExplosionProxyNodes(methodScope, loopScope, successorAddScope, (LoopExitNode) node, nodeOrderId); 541 } else { 542 handleProxyNodes(methodScope, loopScope, (LoopExitNode) node); 543 } 544 545 } else if (node instanceof MergeNode) { 546 handleMergeNode(((MergeNode) node)); 547 548 } else if (node instanceof AbstractEndNode) { 549 LoopScope phiInputScope = loopScope; 550 LoopScope phiNodeScope = loopScope; 551 552 if (methodScope.loopExplosion != LoopExplosionKind.NONE && node instanceof LoopEndNode) { 553 node = handleLoopExplosionEnd(methodScope, loopScope, (LoopEndNode) node); 554 phiNodeScope = loopScope.nextIterations.getLast(); 555 } 556 557 int mergeOrderId = readOrderId(methodScope); 558 AbstractMergeNode merge = (AbstractMergeNode) lookupNode(phiNodeScope, mergeOrderId); 559 if (merge == null) { 560 merge = (AbstractMergeNode) makeStubNode(methodScope, phiNodeScope, mergeOrderId); 561 562 if (merge instanceof LoopBeginNode) { 563 assert phiNodeScope == phiInputScope && phiNodeScope == loopScope; 564 resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId, 565 methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : null, 566 methodScope.loopExplosion != LoopExplosionKind.NONE ? Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length) : loopScope.createdNodes, // 567 methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>(2) : null, // 568 methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE ? EconomicMap.create(Equivalence.DEFAULT) : null); 569 phiInputScope = resultScope; 570 phiNodeScope = resultScope; 571 572 if (methodScope.loopExplosion != LoopExplosionKind.NONE) { 573 registerNode(loopScope, mergeOrderId, null, true, true); 574 } 575 loopScope.nodesToProcess.clear(mergeOrderId); 576 resultScope.nodesToProcess.set(mergeOrderId); 577 } 578 } 579 580 handlePhiFunctions(methodScope, phiInputScope, phiNodeScope, (AbstractEndNode) node, merge); 581 582 } else if (node instanceof Invoke) { 583 InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node); 584 resultScope = handleInvoke(methodScope, loopScope, invokeData); 585 586 } else if (node instanceof ReturnNode || node instanceof UnwindNode) { 587 methodScope.returnAndUnwindNodes.add((ControlSinkNode) node); 588 } else { 589 handleFixedNode(methodScope, loopScope, nodeOrderId, node); 590 } 591 592 return resultScope; 593 } 594 595 protected InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) { 596 ResolvedJavaType contextType = (ResolvedJavaType) readObject(methodScope); 597 int callTargetOrderId = readOrderId(methodScope); 598 int stateAfterOrderId = readOrderId(methodScope); 599 int nextOrderId = readOrderId(methodScope); 600 601 if (invoke instanceof InvokeWithExceptionNode) { 602 int nextNextOrderId = readOrderId(methodScope); 603 int exceptionOrderId = readOrderId(methodScope); 604 int exceptionStateOrderId = readOrderId(methodScope); 605 int exceptionNextOrderId = readOrderId(methodScope); 606 return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, nextNextOrderId, exceptionOrderId, exceptionStateOrderId, 607 exceptionNextOrderId); 608 } else { 609 return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, -1, -1, -1, -1); 610 } 611 } 612 613 /** 614 * {@link Invoke} nodes do not have the {@link CallTargetNode}, {@link FrameState}, and 615 * successors encoded. Instead, this information is provided separately to allow method inlining 616 * without decoding and adding them to the graph upfront. For non-inlined methods, this method 617 * restores the normal state. Subclasses can override it to perform method inlining. 618 * 619 * The return value is the loop scope where decoding should continue. When method inlining 620 * should be performed, the returned loop scope must be a new loop scope for the inlined method. 621 * Without inlining, the original loop scope must be returned. 622 */ 623 protected LoopScope handleInvoke(MethodScope methodScope, LoopScope loopScope, InvokeData invokeData) { 624 assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke"; 625 CallTargetNode callTarget = (CallTargetNode) ensureNodeCreated(methodScope, loopScope, invokeData.callTargetOrderId); 626 appendInvoke(methodScope, loopScope, invokeData, callTarget); 627 return loopScope; 628 } 629 630 protected void appendInvoke(MethodScope methodScope, LoopScope loopScope, InvokeData invokeData, CallTargetNode callTarget) { 631 if (invokeData.invoke instanceof InvokeWithExceptionNode) { 632 ((InvokeWithExceptionNode) invokeData.invoke).setCallTarget(callTarget); 633 } else { 634 ((InvokeNode) invokeData.invoke).setCallTarget(callTarget); 635 } 636 637 assert invokeData.invoke.stateAfter() == null && invokeData.invoke.stateDuring() == null : "FrameState edges are ignored during decoding of Invoke"; 638 invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId)); 639 640 invokeData.invoke.setNext(makeStubNode(methodScope, loopScope, invokeData.nextOrderId)); 641 if (invokeData.invoke instanceof InvokeWithExceptionNode) { 642 ((InvokeWithExceptionNode) invokeData.invoke).setExceptionEdge((AbstractBeginNode) makeStubNode(methodScope, loopScope, invokeData.exceptionOrderId)); 643 } 644 } 645 646 /** 647 * Hook for subclasses to perform simplifications for a non-loop-header control flow merge. 648 * 649 * @param merge The control flow merge. 650 */ 651 protected void handleMergeNode(MergeNode merge) { 652 } 653 654 protected void handleLoopExplosionBegin(MethodScope methodScope, LoopScope loopScope, LoopBeginNode loopBegin) { 655 checkLoopExplosionIteration(methodScope, loopScope); 656 657 List<EndNode> predecessors = loopBegin.forwardEnds().snapshot(); 658 FixedNode successor = loopBegin.next(); 659 FrameState frameState = loopBegin.stateAfter(); 660 661 if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { 662 LoopExplosionState queryState = new LoopExplosionState(frameState, null); 663 LoopExplosionState existingState = loopScope.iterationStates.get(queryState); 664 if (existingState != null) { 665 loopBegin.replaceAtUsagesAndDelete(existingState.merge); 666 successor.safeDelete(); 667 for (EndNode predecessor : predecessors) { 668 existingState.merge.addForwardEnd(predecessor); 669 } 670 return; 671 } 672 } 673 674 MergeNode merge = graph.add(new MergeNode()); 675 methodScope.loopExplosionMerges.add(merge); 676 677 if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { 678 if (loopScope.iterationStates.size() == 0 && loopScope.loopDepth == 1) { 679 if (methodScope.loopExplosionHead != null) { 680 throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion must not have more than one top-level loop", LoopExplosionKind.MERGE_EXPLODE); 681 } 682 methodScope.loopExplosionHead = merge; 683 } 684 685 List<ValueNode> newFrameStateValues = new ArrayList<>(); 686 for (ValueNode frameStateValue : frameState.values) { 687 if (frameStateValue == null || frameStateValue.isConstant() || !graph.isNew(methodScope.methodStartMark, frameStateValue)) { 688 newFrameStateValues.add(frameStateValue); 689 690 } else { 691 ProxyPlaceholder newFrameStateValue = graph.unique(new ProxyPlaceholder(frameStateValue, merge)); 692 newFrameStateValues.add(newFrameStateValue); 693 694 /* 695 * We do not have the orderID of the value anymore, so we need to search through 696 * the complete list of nodes to find a match. 697 */ 698 for (int i = 0; i < loopScope.createdNodes.length; i++) { 699 if (loopScope.createdNodes[i] == frameStateValue) { 700 loopScope.createdNodes[i] = newFrameStateValue; 701 } 702 } 703 704 if (loopScope.initialCreatedNodes != null) { 705 for (int i = 0; i < loopScope.initialCreatedNodes.length; i++) { 706 if (loopScope.initialCreatedNodes[i] == frameStateValue) { 707 loopScope.initialCreatedNodes[i] = newFrameStateValue; 708 } 709 } 710 } 711 } 712 } 713 714 FrameState newFrameState = graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(), 715 frameState.stackSize(), frameState.rethrowException(), frameState.duringCall(), frameState.monitorIds(), frameState.virtualObjectMappings())); 716 717 frameState.replaceAtUsagesAndDelete(newFrameState); 718 frameState = newFrameState; 719 } 720 721 loopBegin.replaceAtUsagesAndDelete(merge); 722 merge.setStateAfter(frameState); 723 merge.setNext(successor); 724 for (EndNode predecessor : predecessors) { 725 merge.addForwardEnd(predecessor); 726 } 727 728 if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) { 729 LoopExplosionState explosionState = new LoopExplosionState(frameState, merge); 730 loopScope.iterationStates.put(explosionState, explosionState); 731 } 732 } 733 734 /** 735 * Hook for subclasses. 736 * 737 * @param methodScope The current method. 738 * @param loopScope The current loop. 739 */ 740 protected void checkLoopExplosionIteration(MethodScope methodScope, LoopScope loopScope) { 741 throw shouldNotReachHere("when subclass uses loop explosion, it needs to implement this method"); 742 } 743 744 protected FixedNode handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope, LoopEndNode loopEnd) { 745 EndNode replacementNode = graph.add(new EndNode()); 746 loopEnd.replaceAtPredecessor(replacementNode); 747 loopEnd.safeDelete(); 748 749 assert methodScope.loopExplosion != LoopExplosionKind.NONE; 750 if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) { 751 int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1; 752 LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, 753 Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), 754 Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), loopScope.nextIterations, loopScope.iterationStates); 755 checkLoopExplosionIteration(methodScope, nextIterationScope); 756 loopScope.nextIterations.addLast(nextIterationScope); 757 registerNode(nextIterationScope, loopScope.loopBeginOrderId, null, true, true); 758 makeStubNode(methodScope, nextIterationScope, loopScope.loopBeginOrderId); 759 } 760 return replacementNode; 761 } 762 763 /** 764 * Hook for subclasses. 765 * 766 * @param methodScope The current method. 767 * @param loopScope The current loop. 768 * @param nodeOrderId The orderId of the node. 769 * @param node The node to be simplified. 770 */ 771 protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) { 772 } 773 774 protected void handleProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopExitNode loopExit) { 775 assert loopExit.stateAfter() == null; 776 int stateAfterOrderId = readOrderId(methodScope); 777 loopExit.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId)); 778 779 int numProxies = methodScope.reader.getUVInt(); 780 for (int i = 0; i < numProxies; i++) { 781 int proxyOrderId = readOrderId(methodScope); 782 ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId); 783 /* 784 * The ProxyNode transports a value from the loop to the outer scope. We therefore 785 * register it in the outer scope. 786 */ 787 if (loopScope.outer.createdNodes != loopScope.createdNodes) { 788 registerNode(loopScope.outer, proxyOrderId, proxy, false, false); 789 } 790 } 791 } 792 793 protected void handleLoopExplosionProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopScope outerScope, LoopExitNode loopExit, int loopExitOrderId) { 794 assert loopExit.stateAfter() == null; 795 int stateAfterOrderId = readOrderId(methodScope); 796 797 BeginNode begin = graph.add(new BeginNode()); 798 799 FixedNode loopExitSuccessor = loopExit.next(); 800 loopExit.replaceAtPredecessor(begin); 801 802 MergeNode loopExitPlaceholder = null; 803 if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth == 1) { 804 /* 805 * This exit might end up as a loop exit of a loop detected after partial evaluation. We 806 * need to be able to create a FrameState and the necessary proxy nodes in this case. 807 */ 808 loopExitPlaceholder = graph.add(new MergeNode()); 809 methodScope.loopExplosionMerges.add(loopExitPlaceholder); 810 811 EndNode end = graph.add(new EndNode()); 812 begin.setNext(end); 813 loopExitPlaceholder.addForwardEnd(end); 814 815 begin = graph.add(new BeginNode()); 816 loopExitPlaceholder.setNext(begin); 817 } 818 819 /* 820 * In the original graph, the loop exit is not a merge node. Multiple exploded loop 821 * iterations now take the same loop exit, so we have to introduce a new merge node to 822 * handle the merge. 823 */ 824 MergeNode merge = null; 825 Node existingExit = lookupNode(outerScope, loopExitOrderId); 826 if (existingExit == null) { 827 /* First loop iteration that exits. No merge necessary yet. */ 828 registerNode(outerScope, loopExitOrderId, begin, false, false); 829 begin.setNext(loopExitSuccessor); 830 831 } else if (existingExit instanceof BeginNode) { 832 /* Second loop iteration that exits. Create the merge. */ 833 merge = graph.add(new MergeNode()); 834 registerNode(outerScope, loopExitOrderId, merge, true, false); 835 /* Add the first iteration. */ 836 EndNode firstEnd = graph.add(new EndNode()); 837 ((BeginNode) existingExit).setNext(firstEnd); 838 merge.addForwardEnd(firstEnd); 839 merge.setNext(loopExitSuccessor); 840 841 } else { 842 /* Subsequent loop iteration. Merge already created. */ 843 merge = (MergeNode) existingExit; 844 } 845 846 if (merge != null) { 847 EndNode end = graph.add(new EndNode()); 848 begin.setNext(end); 849 merge.addForwardEnd(end); 850 } 851 852 /* 853 * Possibly create phi nodes for the original proxy nodes that flow out of the loop. Note 854 * that we definitely do not need a proxy node itself anymore, since the loop was exploded 855 * and is no longer present. 856 */ 857 int numProxies = methodScope.reader.getUVInt(); 858 boolean phiCreated = false; 859 for (int i = 0; i < numProxies; i++) { 860 int proxyOrderId = readOrderId(methodScope); 861 ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId); 862 ValueNode phiInput = proxy.value(); 863 864 if (loopExitPlaceholder != null) { 865 if (!phiInput.isConstant()) { 866 phiInput = graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder)); 867 } 868 registerNode(loopScope, proxyOrderId, phiInput, true, false); 869 } 870 871 ValueNode replacement; 872 ValueNode existing = (ValueNode) outerScope.createdNodes[proxyOrderId]; 873 if (existing == null || existing == phiInput) { 874 /* 875 * We are at the first loop exit, or the proxy carries the same value for all exits. 876 * We do not need a phi node yet. 877 */ 878 registerNode(outerScope, proxyOrderId, phiInput, true, false); 879 replacement = phiInput; 880 881 } else if (!merge.isPhiAtMerge(existing)) { 882 /* Now we have two different values, so we need to create a phi node. */ 883 PhiNode phi; 884 if (proxy instanceof ValueProxyNode) { 885 phi = graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(NodeView.DEFAULT), merge)); 886 } else if (proxy instanceof GuardProxyNode) { 887 phi = graph.addWithoutUnique(new GuardPhiNode(merge)); 888 } else { 889 throw GraalError.shouldNotReachHere(); 890 } 891 /* Add the inputs from all previous exits. */ 892 for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) { 893 phi.addInput(existing); 894 } 895 /* Add the input from this exit. */ 896 phi.addInput(phiInput); 897 registerNode(outerScope, proxyOrderId, phi, true, false); 898 replacement = phi; 899 phiCreated = true; 900 901 } else { 902 /* Phi node has been created before, so just add the new input. */ 903 PhiNode phi = (PhiNode) existing; 904 phi.addInput(phiInput); 905 replacement = phi; 906 } 907 908 proxy.replaceAtUsagesAndDelete(replacement); 909 } 910 911 if (loopExitPlaceholder != null) { 912 registerNode(loopScope, stateAfterOrderId, null, true, true); 913 loopExitPlaceholder.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId)); 914 } 915 916 if (merge != null && (merge.stateAfter() == null || phiCreated)) { 917 FrameState oldStateAfter = merge.stateAfter(); 918 registerNode(outerScope, stateAfterOrderId, null, true, true); 919 merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, outerScope, stateAfterOrderId)); 920 if (oldStateAfter != null) { 921 oldStateAfter.safeDelete(); 922 } 923 } 924 loopExit.safeDelete(); 925 assert loopExitSuccessor.predecessor() == null; 926 if (merge != null) { 927 merge.getNodeClass().getSuccessorEdges().update(merge, null, loopExitSuccessor); 928 } else { 929 begin.getNodeClass().getSuccessorEdges().update(begin, null, loopExitSuccessor); 930 } 931 } 932 933 protected void handlePhiFunctions(MethodScope methodScope, LoopScope phiInputScope, LoopScope phiNodeScope, AbstractEndNode end, AbstractMergeNode merge) { 934 935 if (end instanceof LoopEndNode) { 936 /* 937 * Fix the loop end index and the number of loop ends. When we do canonicalization 938 * during decoding, we can end up with fewer ends than the encoded graph had. And the 939 * order of loop ends can be different. 940 */ 941 int numEnds = ((LoopBeginNode) merge).loopEnds().count(); 942 ((LoopBeginNode) merge).nextEndIndex = numEnds; 943 ((LoopEndNode) end).endIndex = numEnds - 1; 944 945 } else { 946 if (merge.ends == null) { 947 merge.ends = new NodeInputList<>(merge); 948 } 949 merge.addForwardEnd((EndNode) end); 950 } 951 952 /* 953 * We create most phi functions lazily. Canonicalization and simplification during decoding 954 * can lead to dead branches that are not decoded, so we might not need all phi functions 955 * that the original graph contained. Since we process all predecessors before actually 956 * processing the merge node, we have the final phi function when processing the merge node. 957 * The only exception are loop headers of non-exploded loops: since backward branches are 958 * not processed yet when processing the loop body, we need to create all phi functions 959 * upfront. 960 */ 961 boolean lazyPhi = allowLazyPhis() && (!(merge instanceof LoopBeginNode) || methodScope.loopExplosion != LoopExplosionKind.NONE); 962 int numPhis = methodScope.reader.getUVInt(); 963 for (int i = 0; i < numPhis; i++) { 964 int phiInputOrderId = readOrderId(methodScope); 965 int phiNodeOrderId = readOrderId(methodScope); 966 967 ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId); 968 ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId); 969 970 if (existing != null && merge.phiPredecessorCount() == 1) { 971 /* 972 * When exploding loops and the code after the loop (FULL_EXPLODE_UNTIL_RETURN), 973 * then an existing value can already be registered: Parsing of the code before the 974 * loop registers it when preparing for the later merge. The code after the loop, 975 * which starts with a clone of the values that were created before the loop, sees 976 * the stale value when processing the merge the first time. We can safely ignore 977 * the stale value because it will never be needed to be merged (we are exploding 978 * until we hit a return). 979 */ 980 assert methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN && phiNodeScope.loopIteration > 0; 981 existing = null; 982 } 983 984 if (lazyPhi && (existing == null || existing == phiInput)) { 985 /* Phi function not yet necessary. */ 986 registerNode(phiNodeScope, phiNodeOrderId, phiInput, true, false); 987 988 } else if (!merge.isPhiAtMerge(existing)) { 989 /* 990 * Phi function is necessary. Create it and fill it with existing inputs as well as 991 * the new input. 992 */ 993 registerNode(phiNodeScope, phiNodeOrderId, null, true, true); 994 PhiNode phi = (PhiNode) ensureNodeCreated(methodScope, phiNodeScope, phiNodeOrderId); 995 996 phi.setMerge(merge); 997 for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) { 998 phi.addInput(existing); 999 } 1000 phi.addInput(phiInput); 1001 1002 } else { 1003 /* Phi node has been created before, so just add the new input. */ 1004 PhiNode phi = (PhiNode) existing; 1005 phi.addInput(phiInput); 1006 } 1007 } 1008 } 1009 1010 protected boolean allowLazyPhis() { 1011 /* We need to exactly reproduce the encoded graph, including unnecessary phi functions. */ 1012 return false; 1013 } 1014 1015 protected void readProperties(MethodScope methodScope, Node node) { 1016 NodeSourcePosition position = (NodeSourcePosition) readObject(methodScope); 1017 Fields fields = node.getNodeClass().getData(); 1018 for (int pos = 0; pos < fields.getCount(); pos++) { 1019 if (fields.getType(pos).isPrimitive()) { 1020 long primitive = methodScope.reader.getSV(); 1021 fields.setRawPrimitive(node, pos, primitive); 1022 } else { 1023 Object value = readObject(methodScope); 1024 fields.putObject(node, pos, value); 1025 } 1026 } 1027 if (graph.trackNodeSourcePosition() && position != null) { 1028 NodeSourcePosition callerBytecodePosition = methodScope.getCallerBytecodePosition(position); 1029 node.setNodeSourcePosition(callerBytecodePosition); 1030 if (node instanceof DeoptimizingGuard) { 1031 ((DeoptimizingGuard) node).addCallerToNoDeoptSuccessorPosition(callerBytecodePosition.getCaller()); 1032 } 1033 } 1034 } 1035 1036 /** 1037 * Process the input edges of a node. Input nodes that have not yet been created must be 1038 * non-fixed nodes (because fixed nodes are processed in reverse postorder. Such non-fixed nodes 1039 * are created on demand (recursively since they can themselves reference not yet created 1040 * nodes). 1041 */ 1042 protected void makeFixedNodeInputs(MethodScope methodScope, LoopScope loopScope, Node node) { 1043 Edges edges = node.getNodeClass().getInputEdges(); 1044 for (int index = 0; index < edges.getDirectCount(); index++) { 1045 if (skipDirectEdge(node, edges, index)) { 1046 continue; 1047 } 1048 int orderId = readOrderId(methodScope); 1049 Node value = ensureNodeCreated(methodScope, loopScope, orderId); 1050 edges.initializeNode(node, index, value); 1051 if (value != null && !value.isDeleted()) { 1052 edges.update(node, null, value); 1053 1054 } 1055 } 1056 1057 if (node instanceof AbstractMergeNode) { 1058 /* The ends of merge nodes are filled manually when the ends are processed. */ 1059 assert edges.getCount() - edges.getDirectCount() == 1 : "MergeNode has one variable size input (the ends)"; 1060 assert Edges.getNodeList(node, edges.getOffsets(), edges.getDirectCount()) != null : "Input list must have been already created"; 1061 } else { 1062 for (int index = edges.getDirectCount(); index < edges.getCount(); index++) { 1063 int size = methodScope.reader.getSVInt(); 1064 if (size != -1) { 1065 NodeList<Node> nodeList = new NodeInputList<>(node, size); 1066 edges.initializeList(node, index, nodeList); 1067 for (int idx = 0; idx < size; idx++) { 1068 int orderId = readOrderId(methodScope); 1069 Node value = ensureNodeCreated(methodScope, loopScope, orderId); 1070 nodeList.initialize(idx, value); 1071 if (value != null && !value.isDeleted()) { 1072 edges.update(node, null, value); 1073 } 1074 } 1075 } 1076 } 1077 } 1078 } 1079 1080 protected void makeFloatingNodeInputs(MethodScope methodScope, LoopScope loopScope, Node node) { 1081 Edges edges = node.getNodeClass().getInputEdges(); 1082 if (node instanceof PhiNode) { 1083 /* 1084 * The inputs of phi functions are filled manually when the end nodes are processed. 1085 * However, the values must not be null, so initialize them with an empty list. 1086 */ 1087 assert edges.getDirectCount() == 1 : "PhiNode has one direct input (the MergeNode)"; 1088 assert edges.getCount() - edges.getDirectCount() == 1 : "PhiNode has one variable size input (the values)"; 1089 edges.initializeList(node, edges.getDirectCount(), new NodeInputList<>(node)); 1090 } else { 1091 for (int index = 0; index < edges.getDirectCount(); index++) { 1092 int orderId = readOrderId(methodScope); 1093 Node value = ensureNodeCreated(methodScope, loopScope, orderId); 1094 edges.initializeNode(node, index, value); 1095 } 1096 for (int index = edges.getDirectCount(); index < edges.getCount(); index++) { 1097 int size = methodScope.reader.getSVInt(); 1098 if (size != -1) { 1099 NodeList<Node> nodeList = new NodeInputList<>(node, size); 1100 edges.initializeList(node, index, nodeList); 1101 for (int idx = 0; idx < size; idx++) { 1102 int orderId = readOrderId(methodScope); 1103 Node value = ensureNodeCreated(methodScope, loopScope, orderId); 1104 nodeList.initialize(idx, value); 1105 } 1106 } 1107 } 1108 } 1109 } 1110 1111 protected Node ensureNodeCreated(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) { 1112 if (nodeOrderId == GraphEncoder.NULL_ORDER_ID) { 1113 return null; 1114 } 1115 Node node = lookupNode(loopScope, nodeOrderId); 1116 if (node != null) { 1117 return node; 1118 } 1119 1120 node = decodeFloatingNode(methodScope, loopScope, nodeOrderId); 1121 if (node instanceof ProxyNode || node instanceof PhiNode) { 1122 /* 1123 * We need these nodes as they were in the original graph, without any canonicalization 1124 * or value numbering. 1125 */ 1126 node = graph.addWithoutUnique(node); 1127 } else { 1128 /* Allow subclasses to canonicalize and intercept nodes. */ 1129 Node newNode = handleFloatingNodeBeforeAdd(methodScope, loopScope, node); 1130 if (newNode != node) { 1131 releaseFloatingNode(node); 1132 } 1133 1134 if (!newNode.isAlive()) { 1135 newNode = addFloatingNode(methodScope, newNode); 1136 } 1137 node = handleFloatingNodeAfterAdd(methodScope, loopScope, newNode); 1138 } 1139 registerNode(loopScope, nodeOrderId, node, false, false); 1140 return node; 1141 } 1142 1143 protected Node addFloatingNode(@SuppressWarnings("unused") MethodScope methodScope, Node node) { 1144 /* 1145 * We want to exactly reproduce the encoded graph. Even though nodes should be unique in the 1146 * encoded graph, this is not always guaranteed. 1147 */ 1148 return graph.addWithoutUnique(node); 1149 } 1150 1151 /** 1152 * Decodes a non-fixed node, but does not do any post-processing and does not register it. 1153 */ 1154 protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) { 1155 long readerByteIndex = methodScope.reader.getByteIndex(); 1156 1157 methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); 1158 NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()]; 1159 Node node = allocateFloatingNode(nodeClass); 1160 if (node instanceof FixedNode) { 1161 /* 1162 * This is a severe error that will lead to a corrupted graph, so it is better not to 1163 * continue decoding at all. 1164 */ 1165 throw shouldNotReachHere("Not a floating node: " + node.getClass().getName()); 1166 } 1167 1168 /* Read the inputs of the node, possibly creating them recursively. */ 1169 makeFloatingNodeInputs(methodScope, loopScope, node); 1170 1171 /* Read the properties of the node. */ 1172 readProperties(methodScope, node); 1173 /* There must not be any successors to read, since it is a non-fixed node. */ 1174 assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0; 1175 1176 methodScope.reader.setByteIndex(readerByteIndex); 1177 return node; 1178 } 1179 1180 private Node allocateFloatingNode(NodeClass<?> nodeClass) { 1181 ArrayDeque<? extends Node> cachedNodes = reusableFloatingNodes.get(nodeClass); 1182 if (cachedNodes != null) { 1183 Node node = cachedNodes.poll(); 1184 if (node != null) { 1185 return node; 1186 } 1187 } 1188 return nodeClass.allocateInstance(); 1189 } 1190 1191 private void releaseFloatingNode(Node node) { 1192 ArrayDeque<Node> cachedNodes = reusableFloatingNodes.get(node.getNodeClass()); 1193 if (cachedNodes == null) { 1194 cachedNodes = new ArrayDeque<>(2); 1195 reusableFloatingNodes.put(node.getNodeClass(), cachedNodes); 1196 } 1197 cachedNodes.push(node); 1198 } 1199 1200 /** 1201 * Hook for subclasses to process a non-fixed node before it is added to the graph. 1202 * 1203 * @param methodScope The current method. 1204 * @param loopScope The current loop. 1205 * @param node The node to be canonicalized. 1206 * @return The replacement for the node, or the node itself. 1207 */ 1208 protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) { 1209 return node; 1210 } 1211 1212 /** 1213 * Hook for subclasses to process a non-fixed node after it is added to the graph. 1214 * 1215 * If this method replaces a node with another node, it must update its source position if the 1216 * original node has the source position set. 1217 * 1218 * @param methodScope The current method. 1219 * @param loopScope The current loop. 1220 * @param node The node to be canonicalized. 1221 * @return The replacement for the node, or the node itself. 1222 */ 1223 protected Node handleFloatingNodeAfterAdd(MethodScope methodScope, LoopScope loopScope, Node node) { 1224 return node; 1225 } 1226 1227 /** 1228 * Process successor edges of a node. We create the successor nodes so that we can fill the 1229 * successor list, but no properties or edges are loaded yet. That is done when the successor is 1230 * on top of the worklist in {@link #processNextNode}. 1231 */ 1232 protected void makeSuccessorStubs(MethodScope methodScope, LoopScope loopScope, Node node, boolean updatePredecessors) { 1233 Edges edges = node.getNodeClass().getSuccessorEdges(); 1234 for (int index = 0; index < edges.getDirectCount(); index++) { 1235 if (skipDirectEdge(node, edges, index)) { 1236 continue; 1237 } 1238 int orderId = readOrderId(methodScope); 1239 Node value = makeStubNode(methodScope, loopScope, orderId); 1240 edges.initializeNode(node, index, value); 1241 if (updatePredecessors && value != null) { 1242 edges.update(node, null, value); 1243 } 1244 } 1245 for (int index = edges.getDirectCount(); index < edges.getCount(); index++) { 1246 int size = methodScope.reader.getSVInt(); 1247 if (size != -1) { 1248 NodeList<Node> nodeList = new NodeSuccessorList<>(node, size); 1249 edges.initializeList(node, index, nodeList); 1250 for (int idx = 0; idx < size; idx++) { 1251 int orderId = readOrderId(methodScope); 1252 Node value = makeStubNode(methodScope, loopScope, orderId); 1253 nodeList.initialize(idx, value); 1254 if (updatePredecessors && value != null) { 1255 edges.update(node, null, value); 1256 } 1257 } 1258 } 1259 } 1260 } 1261 1262 protected FixedNode makeStubNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) { 1263 if (nodeOrderId == GraphEncoder.NULL_ORDER_ID) { 1264 return null; 1265 } 1266 FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId); 1267 if (node != null) { 1268 return node; 1269 } 1270 1271 long readerByteIndex = methodScope.reader.getByteIndex(); 1272 methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]); 1273 NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()]; 1274 Node stubNode = nodeClass.allocateInstance(); 1275 if (graph.trackNodeSourcePosition()) { 1276 stubNode.setNodeSourcePosition(NodeSourcePosition.placeholder(graph.method())); 1277 } 1278 node = (FixedNode) graph.add(stubNode); 1279 /* Properties and edges are not filled yet, the node remains uninitialized. */ 1280 methodScope.reader.setByteIndex(readerByteIndex); 1281 1282 registerNode(loopScope, nodeOrderId, node, false, false); 1283 loopScope.nodesToProcess.set(nodeOrderId); 1284 return node; 1285 } 1286 1287 protected static boolean skipDirectEdge(Node node, Edges edges, int index) { 1288 if (node instanceof Invoke) { 1289 assert node instanceof InvokeNode || node instanceof InvokeWithExceptionNode : "The only two Invoke node classes. Got " + node.getClass(); 1290 if (edges.type() == Edges.Type.Successors) { 1291 assert edges.getCount() == (node instanceof InvokeWithExceptionNode ? 2 : 1) : "InvokeNode has one successor (next); InvokeWithExceptionNode has two successors (next, exceptionEdge)"; 1292 return true; 1293 } else { 1294 assert edges.type() == Edges.Type.Inputs; 1295 if (edges.getType(index) == CallTargetNode.class) { 1296 return true; 1297 } else if (edges.getType(index) == FrameState.class) { 1298 assert edges.get(node, index) == null || edges.get(node, index) == ((Invoke) node).stateAfter() : "Only stateAfter can be a FrameState during encoding"; 1299 return true; 1300 } 1301 } 1302 } else if (node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class) { 1303 /* The stateAfter of the loop exit is filled manually. */ 1304 return true; 1305 1306 } 1307 return false; 1308 } 1309 1310 protected Node lookupNode(LoopScope loopScope, int nodeOrderId) { 1311 return loopScope.createdNodes[nodeOrderId]; 1312 } 1313 1314 protected void registerNode(LoopScope loopScope, int nodeOrderId, Node node, boolean allowOverwrite, boolean allowNull) { 1315 assert node == null || node.isAlive(); 1316 assert allowNull || node != null; 1317 assert allowOverwrite || lookupNode(loopScope, nodeOrderId) == null; 1318 loopScope.createdNodes[nodeOrderId] = node; 1319 } 1320 1321 protected int readOrderId(MethodScope methodScope) { 1322 return methodScope.reader.getUVInt(); 1323 } 1324 1325 protected Object readObject(MethodScope methodScope) { 1326 return methodScope.encodedGraph.getObject(methodScope.reader.getUVInt()); 1327 } 1328 1329 /** 1330 * Removes unnecessary nodes from the graph after decoding. 1331 * 1332 * @param methodScope The current method. 1333 */ 1334 protected void cleanupGraph(MethodScope methodScope) { 1335 assert verifyEdges(); 1336 } 1337 1338 protected boolean verifyEdges() { 1339 for (Node node : graph.getNodes()) { 1340 assert node.isAlive(); 1341 for (Node i : node.inputs()) { 1342 assert i.isAlive(); 1343 assert i.usages().contains(node); 1344 } 1345 for (Node s : node.successors()) { 1346 assert s.isAlive(); 1347 assert s.predecessor() == node; 1348 } 1349 1350 for (Node usage : node.usages()) { 1351 assert usage.isAlive(); 1352 assert usage.inputs().contains(node) : node + " / " + usage + " / " + usage.inputs().count(); 1353 } 1354 if (node.predecessor() != null) { 1355 assert node.predecessor().isAlive(); 1356 assert node.predecessor().successors().contains(node); 1357 } 1358 } 1359 return true; 1360 } 1361 } 1362 1363 class LoopDetector implements Runnable { 1364 1365 /** 1366 * Information about loops before the actual loop nodes are inserted. 1367 */ 1368 static class Loop { 1369 /** 1370 * The header, i.e., the target of backward branches. 1371 */ 1372 MergeNode header; 1373 /** 1374 * The ends, i.e., the source of backward branches. The {@link EndNode#successors successor} 1375 * is the {@link #header loop header}. 1376 */ 1377 List<EndNode> ends = new ArrayList<>(2); 1378 /** 1379 * Exits of the loop. The successor is a {@link MergeNode} marked in 1380 * {@link MethodScope#loopExplosionMerges}. 1381 */ 1382 List<AbstractEndNode> exits = new ArrayList<>(); 1383 /** 1384 * Set to true when the loop is irreducible, i.e., has multiple entries. See 1385 * {@link #handleIrreducibleLoop} for details on the handling. 1386 */ 1387 boolean irreducible; 1388 } 1389 1390 private final StructuredGraph graph; 1391 private final MethodScope methodScope; 1392 1393 private Loop irreducibleLoopHandler; 1394 private IntegerSwitchNode irreducibleLoopSwitch; 1395 1396 protected LoopDetector(StructuredGraph graph, MethodScope methodScope) { 1397 this.graph = graph; 1398 this.methodScope = methodScope; 1399 } 1400 1401 @Override 1402 public void run() { 1403 DebugContext debug = graph.getDebug(); 1404 debug.dump(DebugContext.DETAILED_LEVEL, graph, "Before loop detection"); 1405 1406 if (methodScope.loopExplosionHead == null) { 1407 /* 1408 * The to-be-exploded loop was not reached during partial evaluation (e.g., because 1409 * there was a deoptimization beforehand), or the method might not even contain a loop. 1410 * This is an uncommon case, but not an error. 1411 */ 1412 return; 1413 } 1414 1415 List<Loop> orderedLoops = findLoops(); 1416 assert orderedLoops.get(orderedLoops.size() - 1) == irreducibleLoopHandler : "outermost loop must be the last element in the list"; 1417 1418 for (Loop loop : orderedLoops) { 1419 if (loop.ends.isEmpty()) { 1420 assert loop == irreducibleLoopHandler; 1421 continue; 1422 } 1423 1424 /* 1425 * The algorithm to find loop exits requires that inner loops have already been 1426 * processed. Therefore, we need to iterate the loops in order (inner loops before outer 1427 * loops), and we cannot find the exits for all loops before we start inserting nodes. 1428 */ 1429 findLoopExits(loop); 1430 1431 if (loop.irreducible) { 1432 handleIrreducibleLoop(loop); 1433 } else { 1434 insertLoopNodes(loop); 1435 } 1436 debug.dump(DebugContext.DETAILED_LEVEL, graph, "After handling of loop %s", loop.header); 1437 } 1438 1439 logIrreducibleLoops(); 1440 debug.dump(DebugContext.DETAILED_LEVEL, graph, "After loop detection"); 1441 } 1442 1443 private List<Loop> findLoops() { 1444 /* Mapping from the loop header node to additional loop information. */ 1445 EconomicMap<MergeNode, Loop> unorderedLoops = EconomicMap.create(Equivalence.IDENTITY); 1446 /* Loops in reverse order of, i.e., inner loops before outer loops. */ 1447 List<Loop> orderedLoops = new ArrayList<>(); 1448 1449 /* 1450 * Ensure we have an outermost loop that we can use to eliminate irreducible loops. This 1451 * loop can remain empty (no ends), in which case it is ignored. 1452 */ 1453 irreducibleLoopHandler = findOrCreateLoop(unorderedLoops, methodScope.loopExplosionHead); 1454 1455 NodeBitMap visited = graph.createNodeBitMap(); 1456 NodeBitMap active = graph.createNodeBitMap(); 1457 Deque<Node> stack = new ArrayDeque<>(); 1458 visited.mark(methodScope.loopExplosionHead); 1459 stack.push(methodScope.loopExplosionHead); 1460 1461 while (!stack.isEmpty()) { 1462 Node current = stack.peek(); 1463 assert visited.isMarked(current); 1464 1465 if (active.isMarked(current)) { 1466 /* We are back-tracking, i.e., all successor nodes have been processed. */ 1467 stack.pop(); 1468 active.clear(current); 1469 1470 if (current instanceof MergeNode) { 1471 Loop loop = unorderedLoops.get((MergeNode) current); 1472 if (loop != null) { 1473 /* 1474 * Since nodes are popped in reverse order that they were pushed, we add 1475 * inner loops before outer loops here. 1476 */ 1477 assert !orderedLoops.contains(loop); 1478 orderedLoops.add(loop); 1479 } 1480 } 1481 1482 } else { 1483 /* 1484 * Process the node. Note that we do not remove the node from the stack, i.e., we 1485 * will peek it again. But the next time the node is marked as active, so we do not 1486 * execute this code again. 1487 */ 1488 active.mark(current); 1489 for (Node successor : current.cfgSuccessors()) { 1490 if (active.isMarked(successor)) { 1491 /* Detected a cycle, i.e., a backward branch of a loop. */ 1492 Loop loop = findOrCreateLoop(unorderedLoops, (MergeNode) successor); 1493 assert !loop.ends.contains(current); 1494 loop.ends.add((EndNode) current); 1495 1496 } else if (visited.isMarked(successor)) { 1497 /* Forward merge into a branch we are already exploring. */ 1498 1499 } else { 1500 /* Forward branch to a node we have not seen yet. */ 1501 visited.mark(successor); 1502 stack.push(successor); 1503 } 1504 } 1505 } 1506 } 1507 return orderedLoops; 1508 } 1509 1510 private Loop findOrCreateLoop(EconomicMap<MergeNode, Loop> unorderedLoops, MergeNode loopHeader) { 1511 assert methodScope.loopExplosionMerges.contains(loopHeader) : loopHeader; 1512 Loop loop = unorderedLoops.get(loopHeader); 1513 if (loop == null) { 1514 loop = new Loop(); 1515 loop.header = loopHeader; 1516 unorderedLoops.put(loopHeader, loop); 1517 } 1518 return loop; 1519 } 1520 1521 private void findLoopExits(Loop loop) { 1522 /* 1523 * Backward marking of loop nodes: Starting with the known loop ends, we mark all nodes that 1524 * are reachable until we hit the loop begin. All successors of loop nodes that are not 1525 * marked as loop nodes themselves are exits of the loop. We mark all successors, and then 1526 * subtract the loop nodes, to find the exits. 1527 */ 1528 1529 List<Node> possibleExits = new ArrayList<>(); 1530 NodeBitMap visited = graph.createNodeBitMap(); 1531 Deque<Node> stack = new ArrayDeque<>(); 1532 for (EndNode loopEnd : loop.ends) { 1533 stack.push(loopEnd); 1534 visited.mark(loopEnd); 1535 } 1536 1537 while (!stack.isEmpty()) { 1538 Node current = stack.pop(); 1539 if (current == loop.header) { 1540 continue; 1541 } 1542 if (!graph.isNew(methodScope.methodStartMark, current)) { 1543 /* 1544 * The current node is before the method that contains the exploded loop. The loop 1545 * must have a second entry point, i.e., it is an irreducible loop. 1546 */ 1547 loop.irreducible = true; 1548 return; 1549 } 1550 1551 for (Node predecessor : current.cfgPredecessors()) { 1552 if (predecessor instanceof LoopExitNode) { 1553 /* 1554 * Inner loop. We do not need to mark every node of it, instead we just continue 1555 * marking at the loop header. 1556 */ 1557 LoopBeginNode innerLoopBegin = ((LoopExitNode) predecessor).loopBegin(); 1558 if (!visited.isMarked(innerLoopBegin)) { 1559 stack.push(innerLoopBegin); 1560 visited.mark(innerLoopBegin); 1561 1562 /* 1563 * All loop exits of the inner loop possibly need a LoopExit of our loop. 1564 * Because we are processing inner loops first, we are guaranteed to already 1565 * have all exits of the inner loop. 1566 */ 1567 for (LoopExitNode exit : innerLoopBegin.loopExits()) { 1568 possibleExits.add(exit); 1569 } 1570 } 1571 1572 } else if (!visited.isMarked(predecessor)) { 1573 stack.push(predecessor); 1574 visited.mark(predecessor); 1575 1576 if (predecessor instanceof ControlSplitNode) { 1577 for (Node succ : predecessor.cfgSuccessors()) { 1578 /* 1579 * We would not need to mark the current node, and would not need to 1580 * mark visited nodes. But it is easier to just mark everything, since 1581 * we subtract all visited nodes in the end anyway. Note that at this 1582 * point we do not have the complete visited information, so we would 1583 * always mark too many possible exits. 1584 */ 1585 possibleExits.add(succ); 1586 } 1587 } 1588 } 1589 } 1590 } 1591 1592 /* 1593 * Now we know all the actual loop exits. Ideally, we would insert LoopExit nodes for them. 1594 * However, a LoopExit needs a valid FrameState that captures the state at the point where 1595 * we exit the loop. During graph decoding, we create a FrameState for every exploded loop 1596 * iteration. We need to do a forward marking until we hit the next such point. This puts 1597 * some nodes into the loop that are actually not part of the loop. 1598 * 1599 * In some cases, we did not create a FrameState during graph decoding: when there was no 1600 * LoopExit in the original loop that we exploded. This happens for code paths that lead 1601 * immediately to a DeoptimizeNode. 1602 * 1603 * Both cases mimic the behavior of the BytecodeParser, which also puts more nodes than 1604 * necessary into a loop because it computes loop information based on bytecodes, before the 1605 * actual parsing. 1606 */ 1607 for (Node succ : possibleExits) { 1608 if (!visited.contains(succ)) { 1609 stack.push(succ); 1610 visited.mark(succ); 1611 assert !methodScope.loopExplosionMerges.contains(succ); 1612 } 1613 } 1614 1615 while (!stack.isEmpty()) { 1616 Node current = stack.pop(); 1617 assert visited.isMarked(current); 1618 assert current instanceof ControlSinkNode || current instanceof LoopEndNode || current.cfgSuccessors().iterator().hasNext() : "Must not reach a node that has not been decoded yet"; 1619 1620 for (Node successor : current.cfgSuccessors()) { 1621 if (visited.isMarked(successor)) { 1622 /* Already processed this successor. */ 1623 1624 } else if (methodScope.loopExplosionMerges.contains(successor)) { 1625 /* 1626 * We have a FrameState for the successor. The LoopExit will be inserted between 1627 * the current node and the successor node. Since the successor node is a 1628 * MergeNode, the current node mus be a AbstractEndNode with only that MergeNode 1629 * as the successor. 1630 */ 1631 assert successor instanceof MergeNode; 1632 assert !loop.exits.contains(current); 1633 loop.exits.add((AbstractEndNode) current); 1634 1635 } else { 1636 /* Node we have not seen yet. */ 1637 visited.mark(successor); 1638 stack.push(successor); 1639 } 1640 } 1641 } 1642 } 1643 1644 private void insertLoopNodes(Loop loop) { 1645 MergeNode merge = loop.header; 1646 FrameState stateAfter = merge.stateAfter().duplicate(); 1647 FixedNode afterMerge = merge.next(); 1648 merge.setNext(null); 1649 EndNode preLoopEnd = graph.add(new EndNode()); 1650 LoopBeginNode loopBegin = graph.add(new LoopBeginNode()); 1651 1652 merge.setNext(preLoopEnd); 1653 /* Add the single non-loop predecessor of the loop header. */ 1654 loopBegin.addForwardEnd(preLoopEnd); 1655 loopBegin.setNext(afterMerge); 1656 loopBegin.setStateAfter(stateAfter); 1657 1658 /* 1659 * Phi functions of the original merge need to be split: inputs that come from forward edges 1660 * remain with the original phi function; inputs that come from backward edges are added to 1661 * new phi functions. 1662 */ 1663 List<PhiNode> mergePhis = merge.phis().snapshot(); 1664 List<PhiNode> loopBeginPhis = new ArrayList<>(mergePhis.size()); 1665 for (int i = 0; i < mergePhis.size(); i++) { 1666 PhiNode mergePhi = mergePhis.get(i); 1667 PhiNode loopBeginPhi = graph.addWithoutUnique(new ValuePhiNode(mergePhi.stamp(NodeView.DEFAULT), loopBegin)); 1668 mergePhi.replaceAtUsages(loopBeginPhi); 1669 /* 1670 * The first input of the new phi function is the original phi function, for the one 1671 * forward edge of the LoopBeginNode. 1672 */ 1673 loopBeginPhi.addInput(mergePhi); 1674 loopBeginPhis.add(loopBeginPhi); 1675 } 1676 1677 for (EndNode endNode : loop.ends) { 1678 for (int i = 0; i < mergePhis.size(); i++) { 1679 PhiNode mergePhi = mergePhis.get(i); 1680 PhiNode loopBeginPhi = loopBeginPhis.get(i); 1681 loopBeginPhi.addInput(mergePhi.valueAt(endNode)); 1682 } 1683 1684 merge.removeEnd(endNode); 1685 LoopEndNode loopEnd = graph.add(new LoopEndNode(loopBegin)); 1686 endNode.replaceAndDelete(loopEnd); 1687 } 1688 1689 /* 1690 * Insert the LoopExit nodes (the easy part) and compute the FrameState for the new exits 1691 * (the difficult part). 1692 */ 1693 for (AbstractEndNode exit : loop.exits) { 1694 AbstractMergeNode loopExplosionMerge = exit.merge(); 1695 assert methodScope.loopExplosionMerges.contains(loopExplosionMerge); 1696 1697 LoopExitNode loopExit = graph.add(new LoopExitNode(loopBegin)); 1698 exit.replaceAtPredecessor(loopExit); 1699 loopExit.setNext(exit); 1700 assignLoopExitState(loopExit, loopExplosionMerge, exit); 1701 } 1702 } 1703 1704 /** 1705 * During graph decoding, we create a FrameState for every exploded loop iteration. This is 1706 * mostly the state that we want, we only need to tweak it a little bit: we need to insert the 1707 * appropriate ProxyNodes for all values that are created inside the loop and that flow out of 1708 * the loop. 1709 */ 1710 private void assignLoopExitState(LoopExitNode loopExit, AbstractMergeNode loopExplosionMerge, AbstractEndNode loopExplosionEnd) { 1711 FrameState oldState = loopExplosionMerge.stateAfter(); 1712 1713 /* Collect all nodes that are in the FrameState at the LoopBegin. */ 1714 EconomicSet<Node> loopBeginValues = EconomicSet.create(Equivalence.IDENTITY); 1715 for (FrameState state = loopExit.loopBegin().stateAfter(); state != null; state = state.outerFrameState()) { 1716 for (ValueNode value : state.values()) { 1717 if (value != null && !value.isConstant() && !loopExit.loopBegin().isPhiAtMerge(value)) { 1718 loopBeginValues.add(ProxyPlaceholder.unwrap(value)); 1719 } 1720 } 1721 } 1722 1723 List<ValueNode> newValues = new ArrayList<>(oldState.values().size()); 1724 for (ValueNode v : oldState.values()) { 1725 ValueNode value = v; 1726 ValueNode realValue = ProxyPlaceholder.unwrap(value); 1727 1728 /* 1729 * The LoopExit is inserted before the existing merge, i.e., separately for every branch 1730 * that leads to the merge. So for phi functions of the merge, we need to take the input 1731 * that corresponds to our branch. 1732 */ 1733 if (realValue instanceof PhiNode && loopExplosionMerge.isPhiAtMerge(realValue)) { 1734 value = ((PhiNode) realValue).valueAt(loopExplosionEnd); 1735 realValue = ProxyPlaceholder.unwrap(value); 1736 } 1737 1738 if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !graph.isNew(methodScope.methodStartMark, realValue)) { 1739 newValues.add(realValue); 1740 } else { 1741 /* 1742 * The node is not in the FrameState of the LoopBegin, i.e., it is a value computed 1743 * inside the loop. 1744 */ 1745 GraalError.guarantee(value instanceof ProxyPlaceholder && ((ProxyPlaceholder) value).proxyPoint == loopExplosionMerge, 1746 "Value flowing out of loop, but we are not prepared to insert a ProxyNode"); 1747 1748 ProxyPlaceholder proxyPlaceholder = (ProxyPlaceholder) value; 1749 ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, graph); 1750 proxyPlaceholder.setValue(proxy); 1751 newValues.add(proxy); 1752 } 1753 } 1754 1755 FrameState newState = new FrameState(oldState.outerFrameState(), oldState.getCode(), oldState.bci, newValues, oldState.localsSize(), oldState.stackSize(), oldState.rethrowException(), 1756 oldState.duringCall(), oldState.monitorIds(), oldState.virtualObjectMappings()); 1757 1758 assert loopExit.stateAfter() == null; 1759 loopExit.setStateAfter(graph.add(newState)); 1760 } 1761 1762 /** 1763 * Graal does not support irreducible loops (loops with more than one entry point). There are 1764 * two ways to make them reducible: 1) duplicate nodes (peel a loop iteration starting at the 1765 * second entry point until we reach the first entry point), or 2) insert a big outer loop 1766 * covering the whole method and build a state machine for the different loop entry points. 1767 * Since node duplication can lead to an exponential explosion of nodes in the worst case, we 1768 * use the second approach. 1769 * 1770 * We already did some preparations to insert a big outer loop: 1771 * {@link MethodScope#loopExplosionHead} is the loop header for the outer loop, and we ensured 1772 * that we have a {@link Loop} data object for it in {@link #irreducibleLoopHandler}. 1773 * 1774 * Now we need to insert the state machine. We have several implementation restrictions to make 1775 * that efficient: 1776 * <ul> 1777 * <li>There must be only one loop variable, i.e., one value that is different in the 1778 * {@link FrameState} of the different loop headers.</li> 1779 * <li>The loop variable must use the primitive {@code int} type, because Graal only has a 1780 * {@link IntegerSwitchNode switch node} for {@code int}.</li> 1781 * <li>The values of the loop variable that are merged are {@link PrimitiveConstant compile time 1782 * constants}.</li> 1783 * </ul> 1784 */ 1785 private void handleIrreducibleLoop(Loop loop) { 1786 assert loop != irreducibleLoopHandler; 1787 1788 FrameState loopState = loop.header.stateAfter(); 1789 FrameState explosionHeadState = irreducibleLoopHandler.header.stateAfter(); 1790 assert loopState.outerFrameState() == explosionHeadState.outerFrameState(); 1791 NodeInputList<ValueNode> loopValues = loopState.values(); 1792 NodeInputList<ValueNode> explosionHeadValues = explosionHeadState.values(); 1793 assert loopValues.size() == explosionHeadValues.size(); 1794 1795 /* 1796 * Find the loop variable, and the value of the loop variable for our loop and the outermost 1797 * loop. There must be exactly one loop variable. 1798 */ 1799 int loopVariableIndex = -1; 1800 ValueNode loopValue = null; 1801 ValueNode explosionHeadValue = null; 1802 for (int i = 0; i < loopValues.size(); i++) { 1803 ValueNode curLoopValue = loopValues.get(i); 1804 ValueNode curExplosionHeadValue = explosionHeadValues.get(i); 1805 1806 if (curLoopValue != curExplosionHeadValue) { 1807 if (loopVariableIndex != -1) { 1808 throw bailout("must have only one variable that is changed in loop. " + loopValue + " != " + explosionHeadValue + " and " + curLoopValue + " != " + curExplosionHeadValue); 1809 } 1810 1811 loopVariableIndex = i; 1812 loopValue = curLoopValue; 1813 explosionHeadValue = curExplosionHeadValue; 1814 } 1815 } 1816 assert loopVariableIndex != -1; 1817 1818 ValuePhiNode loopVariablePhi; 1819 SortedMap<Integer, AbstractBeginNode> dispatchTable = new TreeMap<>(); 1820 AbstractBeginNode unreachableDefaultSuccessor; 1821 if (irreducibleLoopSwitch == null) { 1822 /* 1823 * This is the first irreducible loop. We need to build the initial state machine 1824 * (dispatch for the loop header of the outermost loop). 1825 */ 1826 assert !irreducibleLoopHandler.header.isPhiAtMerge(explosionHeadValue); 1827 assert irreducibleLoopHandler.header.phis().isEmpty(); 1828 1829 /* The new phi function for the loop variable. */ 1830 loopVariablePhi = graph.addWithoutUnique(new ValuePhiNode(explosionHeadValue.stamp(NodeView.DEFAULT).unrestricted(), irreducibleLoopHandler.header)); 1831 for (int i = 0; i < irreducibleLoopHandler.header.phiPredecessorCount(); i++) { 1832 loopVariablePhi.addInput(explosionHeadValue); 1833 } 1834 1835 /* 1836 * Build the new FrameState for the loop header. There is only once change in comparison 1837 * to the old FrameState: the loop variable is replaced with the phi function. 1838 */ 1839 FrameState oldFrameState = explosionHeadState; 1840 List<ValueNode> newFrameStateValues = new ArrayList<>(explosionHeadValues.size()); 1841 for (int i = 0; i < explosionHeadValues.size(); i++) { 1842 if (i == loopVariableIndex) { 1843 newFrameStateValues.add(loopVariablePhi); 1844 } else { 1845 newFrameStateValues.add(explosionHeadValues.get(i)); 1846 } 1847 } 1848 1849 FrameState newFrameState = graph.add( 1850 new FrameState(oldFrameState.outerFrameState(), oldFrameState.getCode(), oldFrameState.bci, newFrameStateValues, oldFrameState.localsSize(), 1851 oldFrameState.stackSize(), oldFrameState.rethrowException(), oldFrameState.duringCall(), oldFrameState.monitorIds(), 1852 oldFrameState.virtualObjectMappings())); 1853 oldFrameState.replaceAtUsages(newFrameState); 1854 1855 /* 1856 * Disconnect the outermost loop header from its loop body, so that we can later on 1857 * insert the switch node. Collect dispatch information for the outermost loop. 1858 */ 1859 FixedNode handlerNext = irreducibleLoopHandler.header.next(); 1860 irreducibleLoopHandler.header.setNext(null); 1861 BeginNode handlerBegin = graph.add(new BeginNode()); 1862 handlerBegin.setNext(handlerNext); 1863 dispatchTable.put(asInt(explosionHeadValue), handlerBegin); 1864 1865 /* 1866 * We know that there will always be a matching key in the switch. But Graal always 1867 * wants a default successor, so we build a dummy block that just deoptimizes. 1868 */ 1869 unreachableDefaultSuccessor = graph.add(new BeginNode()); 1870 DeoptimizeNode deopt = graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode)); 1871 unreachableDefaultSuccessor.setNext(deopt); 1872 1873 } else { 1874 /* 1875 * This is the second or a subsequent irreducible loop, i.e., we already inserted a 1876 * switch node before. We re-create the dispatch state machine of that switch, so that 1877 * we can extend it with one more branch. 1878 */ 1879 assert irreducibleLoopHandler.header.isPhiAtMerge(explosionHeadValue); 1880 assert irreducibleLoopHandler.header.phis().count() == 1 && irreducibleLoopHandler.header.phis().first() == explosionHeadValue; 1881 assert irreducibleLoopSwitch.value() == explosionHeadValue; 1882 1883 /* We can modify the phi function used by the old switch node. */ 1884 loopVariablePhi = (ValuePhiNode) explosionHeadValue; 1885 1886 /* 1887 * We cannot modify the old switch node. Insert all information from the old switch node 1888 * into our temporary data structures for the new, larger, switch node. 1889 */ 1890 for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) { 1891 int key = irreducibleLoopSwitch.keyAt(i).asInt(); 1892 dispatchTable.put(key, irreducibleLoopSwitch.successorAtKey(key)); 1893 } 1894 unreachableDefaultSuccessor = irreducibleLoopSwitch.defaultSuccessor(); 1895 1896 /* Unlink and delete the old switch node, we do not need it anymore. */ 1897 assert irreducibleLoopHandler.header.next() == irreducibleLoopSwitch; 1898 irreducibleLoopHandler.header.setNext(null); 1899 irreducibleLoopSwitch.clearSuccessors(); 1900 irreducibleLoopSwitch.safeDelete(); 1901 } 1902 1903 /* Insert our loop into the dispatch state machine. */ 1904 assert loop.header.phis().isEmpty(); 1905 BeginNode dispatchBegin = graph.add(new BeginNode()); 1906 EndNode dispatchEnd = graph.add(new EndNode()); 1907 dispatchBegin.setNext(dispatchEnd); 1908 loop.header.addForwardEnd(dispatchEnd); 1909 int intLoopValue = asInt(loopValue); 1910 assert !dispatchTable.containsKey(intLoopValue); 1911 dispatchTable.put(intLoopValue, dispatchBegin); 1912 1913 /* Disconnect the ends of our loop and re-connect them to the outermost loop header. */ 1914 for (EndNode end : loop.ends) { 1915 loop.header.removeEnd(end); 1916 irreducibleLoopHandler.ends.add(end); 1917 irreducibleLoopHandler.header.addForwardEnd(end); 1918 loopVariablePhi.addInput(loopValue); 1919 } 1920 1921 /* Build and insert the switch node. */ 1922 irreducibleLoopSwitch = graph.add(createSwitch(loopVariablePhi, dispatchTable, unreachableDefaultSuccessor)); 1923 irreducibleLoopHandler.header.setNext(irreducibleLoopSwitch); 1924 } 1925 1926 private static int asInt(ValueNode node) { 1927 if (!node.isConstant() || node.asJavaConstant().getJavaKind() != JavaKind.Int) { 1928 throw bailout("must have a loop variable of type int. " + node); 1929 } 1930 return node.asJavaConstant().asInt(); 1931 } 1932 1933 private static RuntimeException bailout(String msg) { 1934 throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion %s", LoopExplosionKind.MERGE_EXPLODE, msg); 1935 } 1936 1937 private static IntegerSwitchNode createSwitch(ValuePhiNode switchedValue, SortedMap<Integer, AbstractBeginNode> dispatchTable, AbstractBeginNode defaultSuccessor) { 1938 int numKeys = dispatchTable.size(); 1939 int numSuccessors = numKeys + 1; 1940 1941 AbstractBeginNode[] switchSuccessors = new AbstractBeginNode[numSuccessors]; 1942 int[] switchKeys = new int[numKeys]; 1943 double[] switchKeyProbabilities = new double[numSuccessors]; 1944 int[] switchKeySuccessors = new int[numSuccessors]; 1945 1946 int idx = 0; 1947 for (Map.Entry<Integer, AbstractBeginNode> entry : dispatchTable.entrySet()) { 1948 switchSuccessors[idx] = entry.getValue(); 1949 switchKeys[idx] = entry.getKey(); 1950 switchKeyProbabilities[idx] = 1d / numKeys; 1951 switchKeySuccessors[idx] = idx; 1952 idx++; 1953 } 1954 switchSuccessors[idx] = defaultSuccessor; 1955 /* We know the default branch is never going to be executed. */ 1956 switchKeyProbabilities[idx] = 0; 1957 switchKeySuccessors[idx] = idx; 1958 1959 return new IntegerSwitchNode(switchedValue, switchSuccessors, switchKeys, switchKeyProbabilities, switchKeySuccessors); 1960 } 1961 1962 /** 1963 * Print information about irreducible loops, when enabled with -Dgraal.Log=IrreducibleLoops. 1964 */ 1965 @SuppressWarnings("try") 1966 private void logIrreducibleLoops() { 1967 DebugContext debug = graph.getDebug(); 1968 try (DebugContext.Scope s = debug.scope("IrreducibleLoops")) { 1969 if (debug.isLogEnabled(DebugContext.BASIC_LEVEL) && irreducibleLoopSwitch != null) { 1970 StringBuilder msg = new StringBuilder("Inserted state machine to remove irreducible loops. Dispatching to the following states: "); 1971 String sep = ""; 1972 for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) { 1973 msg.append(sep).append(irreducibleLoopSwitch.keyAt(i).asInt()); 1974 sep = ", "; 1975 } 1976 debug.log(DebugContext.BASIC_LEVEL, "%s", msg); 1977 } 1978 } 1979 } 1980 }