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