1 /* 2 * Copyright (c) 2013, 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.phases.common; 24 25 import org.graalvm.compiler.core.common.cfg.Loop; 26 import org.graalvm.compiler.debug.Debug; 27 import org.graalvm.compiler.debug.DebugCloseable; 28 import org.graalvm.compiler.graph.Node; 29 import org.graalvm.compiler.nodes.AbstractBeginNode; 30 import org.graalvm.compiler.nodes.BeginNode; 31 import org.graalvm.compiler.nodes.DeoptimizeNode; 32 import org.graalvm.compiler.nodes.FixedWithNextNode; 33 import org.graalvm.compiler.nodes.GuardNode; 34 import org.graalvm.compiler.nodes.IfNode; 35 import org.graalvm.compiler.nodes.LoopBeginNode; 36 import org.graalvm.compiler.nodes.LoopExitNode; 37 import org.graalvm.compiler.nodes.StructuredGraph; 38 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage; 39 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult; 40 import org.graalvm.compiler.nodes.cfg.Block; 41 import org.graalvm.compiler.phases.BasePhase; 42 import org.graalvm.compiler.phases.graph.ScheduledNodeIterator; 43 import org.graalvm.compiler.phases.schedule.SchedulePhase; 44 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy; 45 import org.graalvm.compiler.phases.tiers.MidTierContext; 46 47 /** 48 * This phase lowers {@link GuardNode GuardNodes} into corresponding control-flow structure and 49 * {@link DeoptimizeNode DeoptimizeNodes}. 50 * 51 * This allow to enter the {@link GuardsStage#FIXED_DEOPTS FIXED_DEOPTS} stage of the graph where 52 * all node that may cause deoptimization are fixed. 53 * <p> 54 * It first makes a schedule in order to know where the control flow should be placed. Then, for 55 * each block, it applies two passes. The first one tries to replace null-check guards with implicit 56 * null checks performed by access to the objects that need to be null checked. The second phase 57 * does the actual control-flow expansion of the remaining {@link GuardNode GuardNodes}. 58 */ 59 public class GuardLoweringPhase extends BasePhase<MidTierContext> { 60 61 private static class LowerGuards extends ScheduledNodeIterator { 62 63 private final Block block; 64 private boolean useGuardIdAsDebugId; 65 66 LowerGuards(Block block, boolean useGuardIdAsDebugId) { 67 this.block = block; 68 this.useGuardIdAsDebugId = useGuardIdAsDebugId; 69 } 70 71 @Override 72 protected void processNode(Node node) { 73 if (node instanceof GuardNode) { 74 GuardNode guard = (GuardNode) node; 75 FixedWithNextNode lowered = guard.lowerGuard(); 76 if (lowered != null) { 77 replaceCurrent(lowered); 78 } else { 79 lowerToIf(guard); 80 } 81 } 82 } 83 84 @SuppressWarnings("try") 85 private void lowerToIf(GuardNode guard) { 86 try (DebugCloseable position = guard.withNodeSourcePosition()) { 87 StructuredGraph graph = guard.graph(); 88 AbstractBeginNode fastPath = graph.add(new BeginNode()); 89 @SuppressWarnings("deprecation") 90 int debugId = useGuardIdAsDebugId ? guard.getId() : DeoptimizeNode.DEFAULT_DEBUG_ID; 91 DeoptimizeNode deopt = graph.add(new DeoptimizeNode(guard.getAction(), guard.getReason(), debugId, guard.getSpeculation(), null)); 92 AbstractBeginNode deoptBranch = BeginNode.begin(deopt); 93 AbstractBeginNode trueSuccessor; 94 AbstractBeginNode falseSuccessor; 95 insertLoopExits(deopt); 96 if (guard.isNegated()) { 97 trueSuccessor = deoptBranch; 98 falseSuccessor = fastPath; 99 } else { 100 trueSuccessor = fastPath; 101 falseSuccessor = deoptBranch; 102 } 103 IfNode ifNode = graph.add(new IfNode(guard.getCondition(), trueSuccessor, falseSuccessor, trueSuccessor == fastPath ? 1 : 0)); 104 guard.replaceAndDelete(fastPath); 105 insert(ifNode, fastPath); 106 } 107 } 108 109 private void insertLoopExits(DeoptimizeNode deopt) { 110 Loop<Block> loop = block.getLoop(); 111 StructuredGraph graph = deopt.graph(); 112 while (loop != null) { 113 LoopExitNode exit = graph.add(new LoopExitNode((LoopBeginNode) loop.getHeader().getBeginNode())); 114 graph.addBeforeFixed(deopt, exit); 115 loop = loop.getParent(); 116 } 117 } 118 } 119 120 @Override 121 protected void run(StructuredGraph graph, MidTierContext context) { 122 if (graph.getGuardsStage().allowsFloatingGuards()) { 123 SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST); 124 schedulePhase.apply(graph); 125 ScheduleResult schedule = graph.getLastSchedule(); 126 127 for (Block block : schedule.getCFG().getBlocks()) { 128 processBlock(block, schedule); 129 } 130 graph.setGuardsStage(GuardsStage.FIXED_DEOPTS); 131 } 132 133 assert assertNoGuardsLeft(graph); 134 } 135 136 private static boolean assertNoGuardsLeft(StructuredGraph graph) { 137 assert graph.getNodes().filter(GuardNode.class).isEmpty(); 138 return true; 139 } 140 141 private static void processBlock(Block block, ScheduleResult schedule) { 142 new LowerGuards(block, Debug.isDumpEnabledForMethod() || Debug.isLogEnabledForMethod()).processNodes(block, schedule); 143 } 144 }