1 /* 2 * Copyright (c) 2013, 2019, 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.phases.common; 26 27 import java.util.Iterator; 28 import java.util.LinkedList; 29 import java.util.List; 30 31 import org.graalvm.compiler.core.common.cfg.Loop; 32 import org.graalvm.compiler.core.common.type.StampFactory; 33 import org.graalvm.compiler.debug.DebugCloseable; 34 import org.graalvm.compiler.nodes.AbstractDeoptimizeNode; 35 import org.graalvm.compiler.nodes.AbstractMergeNode; 36 import org.graalvm.compiler.nodes.DynamicDeoptimizeNode; 37 import org.graalvm.compiler.nodes.EndNode; 38 import org.graalvm.compiler.nodes.FrameState; 39 import org.graalvm.compiler.nodes.LoopBeginNode; 40 import org.graalvm.compiler.nodes.LoopExitNode; 41 import org.graalvm.compiler.nodes.MergeNode; 42 import org.graalvm.compiler.nodes.PhiNode; 43 import org.graalvm.compiler.nodes.StructuredGraph; 44 import org.graalvm.compiler.nodes.ValueNode; 45 import org.graalvm.compiler.nodes.ValuePhiNode; 46 import org.graalvm.compiler.nodes.cfg.Block; 47 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 48 import org.graalvm.compiler.phases.BasePhase; 49 import org.graalvm.compiler.phases.tiers.MidTierContext; 50 51 /** 52 * This phase tries to find {@link AbstractDeoptimizeNode DeoptimizeNodes} which use the same 53 * {@link FrameState} and merges them together. 54 */ 55 public class DeoptimizationGroupingPhase extends BasePhase<MidTierContext> { 56 57 @Override 58 @SuppressWarnings("try") 59 protected void run(StructuredGraph graph, MidTierContext context) { 60 ControlFlowGraph cfg = null; 61 for (FrameState fs : graph.getNodes(FrameState.TYPE)) { 62 Iterator<AbstractDeoptimizeNode> iterator = fs.usages().filter(AbstractDeoptimizeNode.class).iterator(); 63 if (!iterator.hasNext()) { 64 // No deopt 65 continue; 66 } 67 AbstractDeoptimizeNode first = iterator.next(); 68 if (!iterator.hasNext()) { 69 // Only 1 deopt 70 continue; 71 } 72 // There is more than one deopt, create a merge 73 if (cfg == null) { 74 cfg = ControlFlowGraph.compute(graph, true, true, false, false); 75 } 76 AbstractMergeNode merge = graph.add(new MergeNode()); 77 EndNode firstEnd = graph.add(new EndNode()); 78 ValueNode actionAndReason = first.getActionAndReason(context.getMetaAccess()); 79 ValueNode speculation = first.getSpeculation(context.getMetaAccess()); 80 PhiNode reasonActionPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(actionAndReason.getStackKind()), merge)); 81 PhiNode speculationPhi = graph.addWithoutUnique(new ValuePhiNode(StampFactory.forKind(speculation.getStackKind()), merge)); 82 merge.addForwardEnd(firstEnd); 83 reasonActionPhi.addInput(actionAndReason); 84 speculationPhi.addInput(speculation); 85 first.replaceAtPredecessor(firstEnd); 86 exitLoops(first, firstEnd, cfg); 87 DynamicDeoptimizeNode dynamicDeopt; 88 try (DebugCloseable position = first.withNodeSourcePosition()) { 89 dynamicDeopt = new DynamicDeoptimizeNode(reasonActionPhi, speculationPhi); 90 merge.setNext(graph.add(dynamicDeopt)); 91 } 92 List<AbstractDeoptimizeNode> obsoletes = new LinkedList<>(); 93 obsoletes.add(first); 94 95 do { 96 AbstractDeoptimizeNode deopt = iterator.next(); 97 EndNode newEnd = graph.add(new EndNode()); 98 merge.addForwardEnd(newEnd); 99 reasonActionPhi.addInput(deopt.getActionAndReason(context.getMetaAccess())); 100 speculationPhi.addInput(deopt.getSpeculation(context.getMetaAccess())); 101 deopt.replaceAtPredecessor(newEnd); 102 exitLoops(deopt, newEnd, cfg); 103 obsoletes.add(deopt); 104 } while (iterator.hasNext()); 105 106 dynamicDeopt.setStateBefore(fs); 107 for (AbstractDeoptimizeNode obsolete : obsoletes) { 108 obsolete.safeDelete(); 109 } 110 } 111 } 112 113 private static void exitLoops(AbstractDeoptimizeNode deopt, EndNode end, ControlFlowGraph cfg) { 114 Block block = cfg.blockFor(deopt); 115 Loop<Block> loop = block.getLoop(); 116 while (loop != null) { 117 end.graph().addBeforeFixed(end, end.graph().add(new LoopExitNode((LoopBeginNode) loop.getHeader().getBeginNode()))); 118 loop = loop.getParent(); 119 } 120 } 121 122 @Override 123 public float codeSizeIncrease() { 124 return 2.5f; 125 } 126 }