1 /*
   2  * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 package org.graalvm.compiler.nodes;
  26 
  27 import org.graalvm.compiler.core.common.type.StampFactory;
  28 import org.graalvm.compiler.debug.DebugCloseable;
  29 import org.graalvm.compiler.graph.NodeClass;
  30 import org.graalvm.compiler.graph.NodeSourcePosition;
  31 import org.graalvm.compiler.graph.spi.Simplifiable;
  32 import org.graalvm.compiler.graph.spi.SimplifierTool;
  33 import org.graalvm.compiler.nodeinfo.InputType;
  34 import org.graalvm.compiler.nodeinfo.NodeInfo;
  35 import org.graalvm.compiler.nodeinfo.Verbosity;
  36 import org.graalvm.compiler.nodes.extended.GuardingNode;
  37 import org.graalvm.compiler.nodes.util.GraphUtil;
  38 
  39 import jdk.vm.ci.meta.DeoptimizationAction;
  40 import jdk.vm.ci.meta.DeoptimizationReason;
  41 import jdk.vm.ci.meta.SpeculationLog.Speculation;
  42 
  43 @NodeInfo
  44 public abstract class AbstractFixedGuardNode extends DeoptimizingFixedWithNextNode implements Simplifiable, GuardingNode, DeoptimizingGuard {
  45 
  46     public static final NodeClass<AbstractFixedGuardNode> TYPE = NodeClass.create(AbstractFixedGuardNode.class);
  47     @Input(InputType.Condition) protected LogicNode condition;
  48     protected DeoptimizationReason reason;
  49     protected DeoptimizationAction action;
  50     protected Speculation speculation;
  51     protected boolean negated;
  52     protected NodeSourcePosition noDeoptSuccessorPosition;
  53 
  54     @Override
  55     public LogicNode getCondition() {
  56         return condition;
  57     }
  58 
  59     public LogicNode condition() {
  60         return getCondition();
  61     }
  62 
  63     @Override
  64     public void setCondition(LogicNode x, boolean negated) {
  65         updateUsages(condition, x);
  66         condition = x;
  67         this.negated = negated;
  68     }
  69 
  70     protected AbstractFixedGuardNode(NodeClass<? extends AbstractFixedGuardNode> c, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, Speculation speculation,
  71                     boolean negated) {
  72         super(c, StampFactory.forVoid());
  73         this.action = action;
  74         assert speculation != null;
  75         this.speculation = speculation;
  76         this.negated = negated;
  77         this.condition = condition;
  78         this.reason = deoptReason;
  79     }
  80 
  81     protected AbstractFixedGuardNode(NodeClass<? extends AbstractFixedGuardNode> c, LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, Speculation speculation,
  82                     boolean negated, NodeSourcePosition noDeoptSuccessorPosition) {
  83         this(c, condition, deoptReason, action, speculation, negated);
  84         this.noDeoptSuccessorPosition = noDeoptSuccessorPosition;
  85     }
  86 
  87     @Override
  88     public DeoptimizationReason getReason() {
  89         return reason;
  90     }
  91 
  92     @Override
  93     public DeoptimizationAction getAction() {
  94         return action;
  95     }
  96 
  97     @Override
  98     public Speculation getSpeculation() {
  99         return speculation;
 100     }
 101 
 102     @Override
 103     public boolean isNegated() {
 104         return negated;
 105     }
 106 
 107     @Override
 108     public String toString(Verbosity verbosity) {
 109         if (verbosity == Verbosity.Name && negated) {
 110             return "!" + super.toString(verbosity);
 111         } else {
 112             return super.toString(verbosity);
 113         }
 114     }
 115 
 116     @Override
 117     public void simplify(SimplifierTool tool) {
 118         while (condition instanceof LogicNegationNode) {
 119             LogicNegationNode negation = (LogicNegationNode) condition;
 120             setCondition(negation.getValue(), !negated);
 121         }
 122     }
 123 
 124     @SuppressWarnings("try")
 125     public DeoptimizeNode lowerToIf() {
 126         try (DebugCloseable position = this.withNodeSourcePosition()) {
 127             FixedNode currentNext = next();
 128             setNext(null);
 129             if (currentNext instanceof AbstractBeginNode && currentNext instanceof StateSplit && ((StateSplit) currentNext).stateAfter() != null) {
 130                 // Force an extra BeginNode in case any guarded Nodes are inputs to the StateSplit
 131                 BeginNode begin = graph().add(new BeginNode());
 132                 begin.setNodeSourcePosition(getNoDeoptSuccessorPosition());
 133                 begin.setNext(currentNext);
 134                 currentNext = begin;
 135             }
 136 
 137             DeoptimizeNode deopt = graph().add(new DeoptimizeNode(action, reason, speculation));
 138             deopt.setStateBefore(stateBefore());
 139             IfNode ifNode;
 140             AbstractBeginNode noDeoptSuccessor;
 141             if (negated) {
 142                 ifNode = graph().add(new IfNode(condition, deopt, currentNext, 0));
 143                 noDeoptSuccessor = ifNode.falseSuccessor();
 144             } else {
 145                 ifNode = graph().add(new IfNode(condition, currentNext, deopt, 1));
 146                 noDeoptSuccessor = ifNode.trueSuccessor();
 147             }
 148             noDeoptSuccessor.setNodeSourcePosition(getNoDeoptSuccessorPosition());
 149             ((FixedWithNextNode) predecessor()).setNext(ifNode);
 150             this.replaceAtUsages(noDeoptSuccessor);
 151             GraphUtil.killWithUnusedFloatingInputs(this);
 152 
 153             return deopt;
 154         }
 155     }
 156 
 157     @Override
 158     public boolean canDeoptimize() {
 159         return true;
 160     }
 161 
 162     @Override
 163     public void setAction(DeoptimizationAction action) {
 164         this.action = action;
 165     }
 166 
 167     @Override
 168     public void setReason(DeoptimizationReason reason) {
 169         this.reason = reason;
 170     }
 171 
 172     @Override
 173     public NodeSourcePosition getNoDeoptSuccessorPosition() {
 174         return noDeoptSuccessorPosition;
 175     }
 176 
 177     @Override
 178     public void setNoDeoptSuccessorPosition(NodeSourcePosition noDeoptSuccessorPosition) {
 179         this.noDeoptSuccessorPosition = noDeoptSuccessorPosition;
 180     }
 181 }