src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java
changeset 48861 47f19ff9903c
parent 47216 71c04702a3d5
child 49451 e06f9607f370
equal deleted inserted replaced
48860:5bce1b7e7800 48861:47f19ff9903c
    24 
    24 
    25 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
    25 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
    26 
    26 
    27 import java.util.List;
    27 import java.util.List;
    28 
    28 
       
    29 import org.graalvm.compiler.core.common.GraalOptions;
    29 import org.graalvm.compiler.debug.DebugCloseable;
    30 import org.graalvm.compiler.debug.DebugCloseable;
    30 import org.graalvm.compiler.debug.DebugContext;
       
    31 import org.graalvm.compiler.graph.Node;
    31 import org.graalvm.compiler.graph.Node;
    32 import org.graalvm.compiler.graph.spi.SimplifierTool;
    32 import org.graalvm.compiler.graph.spi.SimplifierTool;
    33 import org.graalvm.compiler.nodeinfo.InputType;
    33 import org.graalvm.compiler.nodeinfo.InputType;
    34 import org.graalvm.compiler.nodes.AbstractBeginNode;
    34 import org.graalvm.compiler.nodes.AbstractBeginNode;
    35 import org.graalvm.compiler.nodes.AbstractEndNode;
    35 import org.graalvm.compiler.nodes.AbstractEndNode;
    44 import org.graalvm.compiler.nodes.GuardNode;
    44 import org.graalvm.compiler.nodes.GuardNode;
    45 import org.graalvm.compiler.nodes.IfNode;
    45 import org.graalvm.compiler.nodes.IfNode;
    46 import org.graalvm.compiler.nodes.LogicNode;
    46 import org.graalvm.compiler.nodes.LogicNode;
    47 import org.graalvm.compiler.nodes.LoopExitNode;
    47 import org.graalvm.compiler.nodes.LoopExitNode;
    48 import org.graalvm.compiler.nodes.ProxyNode;
    48 import org.graalvm.compiler.nodes.ProxyNode;
       
    49 import org.graalvm.compiler.nodes.StartNode;
       
    50 import org.graalvm.compiler.nodes.StaticDeoptimizingNode;
    49 import org.graalvm.compiler.nodes.StructuredGraph;
    51 import org.graalvm.compiler.nodes.StructuredGraph;
    50 import org.graalvm.compiler.nodes.ValueNode;
    52 import org.graalvm.compiler.nodes.ValueNode;
    51 import org.graalvm.compiler.nodes.ValuePhiNode;
    53 import org.graalvm.compiler.nodes.ValuePhiNode;
    52 import org.graalvm.compiler.nodes.calc.CompareNode;
    54 import org.graalvm.compiler.nodes.calc.CompareNode;
    53 import org.graalvm.compiler.nodes.spi.LoweringProvider;
    55 import org.graalvm.compiler.nodes.spi.LoweringProvider;
    55 import org.graalvm.compiler.phases.BasePhase;
    57 import org.graalvm.compiler.phases.BasePhase;
    56 import org.graalvm.compiler.phases.tiers.PhaseContext;
    58 import org.graalvm.compiler.phases.tiers.PhaseContext;
    57 
    59 
    58 import jdk.vm.ci.meta.Constant;
    60 import jdk.vm.ci.meta.Constant;
    59 import jdk.vm.ci.meta.DeoptimizationAction;
    61 import jdk.vm.ci.meta.DeoptimizationAction;
    60 import jdk.vm.ci.meta.DeoptimizationReason;
       
    61 import jdk.vm.ci.meta.JavaConstant;
       
    62 
    62 
    63 /**
    63 /**
    64  * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
    64  * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
    65  * {@link ControlSplitNode ControlSplitNodes} with {@link FixedGuardNode FixedGuardNodes}.
    65  * {@link ControlSplitNode ControlSplitNodes} with {@link FixedGuardNode FixedGuardNodes}.
    66  *
    66  *
    75 public class ConvertDeoptimizeToGuardPhase extends BasePhase<PhaseContext> {
    75 public class ConvertDeoptimizeToGuardPhase extends BasePhase<PhaseContext> {
    76     @Override
    76     @Override
    77     @SuppressWarnings("try")
    77     @SuppressWarnings("try")
    78     protected void run(final StructuredGraph graph, PhaseContext context) {
    78     protected void run(final StructuredGraph graph, PhaseContext context) {
    79         assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
    79         assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
       
    80         assert !graph.getGuardsStage().areFrameStatesAtDeopts() : graph.getGuardsStage();
    80 
    81 
    81         for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) {
    82         for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) {
    82             assert d.isAlive();
    83             assert d.isAlive();
    83             // Can only aggressively move deoptimization point if their action implies that
    84             if (d.getAction() == DeoptimizationAction.None) {
    84             // the deoptimization will not be triggered again. Example for such action is
    85                 continue;
    85             // reprofiling or recompiling with less aggressive options.
    86             }
    86             if (d.action() != DeoptimizationAction.None) {
    87             try (DebugCloseable closable = d.withNodeSourcePosition()) {
    87                 try (DebugCloseable closable = d.withNodeSourcePosition()) {
    88                 propagateFixed(d, d, context != null ? context.getLowerer() : null);
    88                     visitDeoptBegin(AbstractBeginNode.prevBegin(d), d.action(), d.reason(), d.getSpeculation(), graph, context != null ? context.getLowerer() : null);
    89             }
    89                 }
       
    90             }
       
    91 
       
    92         }
    90         }
    93 
    91 
    94         if (context != null) {
    92         if (context != null) {
    95             for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) {
    93             for (FixedGuardNode fixedGuard : graph.getNodes(FixedGuardNode.TYPE)) {
    96                 try (DebugCloseable closable = fixedGuard.withNodeSourcePosition()) {
    94                 try (DebugCloseable closable = fixedGuard.withNodeSourcePosition()) {
   152                 ys = y.asConstant();
   150                 ys = y.asConstant();
   153             } else {
   151             } else {
   154                 ys = yPhi.valueAt(mergePredecessor).asConstant();
   152                 ys = yPhi.valueAt(mergePredecessor).asConstant();
   155             }
   153             }
   156             if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
   154             if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
   157                 visitDeoptBegin(AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), fixedGuard.getSpeculation(), fixedGuard.graph(), context.getLowerer());
   155                 propagateFixed(mergePredecessor, fixedGuard, context.getLowerer());
   158             }
   156             }
   159         }
   157         }
   160     }
   158     }
   161 
   159 
   162     private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, JavaConstant speculation, StructuredGraph graph,
   160     private void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, LoweringProvider loweringProvider) {
   163                     LoweringProvider loweringProvider) {
   161         Node current = from;
   164         if (deoptBegin.predecessor() instanceof AbstractBeginNode) {
   162         while (current != null) {
   165             /*
   163             if (GraalOptions.GuardPriorities.getValue(from.getOptions()) && current instanceof FixedGuardNode) {
   166              * Walk up chains of LoopExitNodes to the "real" BeginNode that leads to deoptimization.
   164                 FixedGuardNode otherGuard = (FixedGuardNode) current;
   167              */
   165                 if (otherGuard.computePriority().isHigherPriorityThan(deopt.computePriority())) {
   168             visitDeoptBegin((AbstractBeginNode) deoptBegin.predecessor(), deoptAction, deoptReason, speculation, graph, loweringProvider);
   166                     moveAsDeoptAfter(otherGuard, deopt);
   169             return;
   167                     return;
   170         }
   168                 }
   171 
   169             } else if (current instanceof AbstractBeginNode) {
   172         DebugContext debug = deoptBegin.getDebug();
   170                 if (current instanceof AbstractMergeNode) {
   173         if (deoptBegin instanceof AbstractMergeNode) {
   171                     AbstractMergeNode mergeNode = (AbstractMergeNode) current;
   174             AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin;
   172                     FixedNode next = mergeNode.next();
   175             debug.log("Visiting %s", mergeNode);
   173                     while (mergeNode.isAlive()) {
   176             FixedNode next = mergeNode.next();
   174                         AbstractEndNode end = mergeNode.forwardEnds().first();
   177             while (mergeNode.isAlive()) {
   175                         propagateFixed(end, deopt, loweringProvider);
   178                 AbstractEndNode end = mergeNode.forwardEnds().first();
   176                     }
   179                 AbstractBeginNode newBeginNode = AbstractBeginNode.prevBegin(end);
   177                     assert next.isAlive();
   180                 visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider);
   178                     propagateFixed(next, deopt, loweringProvider);
   181             }
   179                     return;
   182             assert next.isAlive();
   180                 } else if (current.predecessor() instanceof IfNode) {
   183             AbstractBeginNode newBeginNode = AbstractBeginNode.prevBegin(next);
   181                     IfNode ifNode = (IfNode) current.predecessor();
   184             visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider);
   182                     StructuredGraph graph = ifNode.graph();
   185             return;
   183                     LogicNode conditionNode = ifNode.condition();
   186         } else if (deoptBegin.predecessor() instanceof IfNode) {
   184                     boolean negateGuardCondition = current == ifNode.trueSuccessor();
   187             IfNode ifNode = (IfNode) deoptBegin.predecessor();
   185                     FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition));
   188             LogicNode conditionNode = ifNode.condition();
   186                     FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
   189             FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deoptReason, deoptAction, speculation, deoptBegin == ifNode.trueSuccessor()));
   187                     AbstractBeginNode survivingSuccessor;
   190             FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
   188                     if (negateGuardCondition) {
   191             AbstractBeginNode survivingSuccessor;
   189                         survivingSuccessor = ifNode.falseSuccessor();
   192             if (deoptBegin == ifNode.trueSuccessor()) {
   190                     } else {
   193                 survivingSuccessor = ifNode.falseSuccessor();
   191                         survivingSuccessor = ifNode.trueSuccessor();
   194             } else {
   192                     }
   195                 survivingSuccessor = ifNode.trueSuccessor();
   193                     graph.removeSplitPropagate(ifNode, survivingSuccessor);
   196             }
   194 
   197             graph.removeSplitPropagate(ifNode, survivingSuccessor);
   195                     Node newGuard = guard;
   198 
   196                     if (survivingSuccessor instanceof LoopExitNode) {
   199             Node newGuard = guard;
   197                         newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
   200             if (survivingSuccessor instanceof LoopExitNode) {
   198                     }
   201                 newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
   199                     survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
   202             }
   200 
   203             survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
   201                     graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor);
   204 
   202                     FixedNode next = pred.next();
   205             debug.log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, survivingSuccessor);
   203                     pred.setNext(guard);
   206             FixedNode next = pred.next();
   204                     guard.setNext(next);
   207             pred.setNext(guard);
   205                     SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
   208             guard.setNext(next);
   206                     survivingSuccessor.simplify(simplifierTool);
   209             SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
   207                     return;
   210             survivingSuccessor.simplify(simplifierTool);
   208                 } else if (current.predecessor() == null || current.predecessor() instanceof ControlSplitNode) {
   211             return;
   209                     assert current.predecessor() != null || (current instanceof StartNode && current == ((AbstractBeginNode) current).graph().start());
   212         }
   210                     moveAsDeoptAfter((AbstractBeginNode) current, deopt);
   213 
   211                     return;
   214         // We could not convert the control split - at least cut off control flow after the split.
   212                 }
   215         FixedWithNextNode deoptPred = deoptBegin;
   213             }
   216         FixedNode next = deoptPred.next();
   214             current = current.predecessor();
   217 
   215         }
   218         if (!(next instanceof DeoptimizeNode)) {
   216     }
   219             DeoptimizeNode newDeoptNode = graph.add(new DeoptimizeNode(deoptAction, deoptReason, speculation));
   217 
   220             deoptPred.setNext(newDeoptNode);
   218     private static void moveAsDeoptAfter(FixedWithNextNode node, StaticDeoptimizingNode deopt) {
   221             assert deoptPred == newDeoptNode.predecessor();
   219         FixedNode next = node.next();
       
   220         if (next != deopt.asNode()) {
       
   221             node.setNext(node.graph().add(new DeoptimizeNode(deopt.getAction(), deopt.getReason(), deopt.getSpeculation())));
   222             GraphUtil.killCFG(next);
   222             GraphUtil.killCFG(next);
   223         }
   223         }
   224     }
   224     }
   225 }
   225 }