1 /*
   2  * Copyright (c) 2011, 2014, 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.nodeinfo.InputType.Condition;
  26 import static org.graalvm.compiler.nodeinfo.InputType.Guard;
  27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  29 
  30 import org.graalvm.compiler.core.common.type.StampFactory;
  31 import org.graalvm.compiler.graph.IterableNodeType;
  32 import org.graalvm.compiler.graph.Node;
  33 import org.graalvm.compiler.graph.NodeClass;
  34 import org.graalvm.compiler.graph.spi.Canonicalizable;
  35 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  36 import org.graalvm.compiler.nodeinfo.NodeInfo;
  37 import org.graalvm.compiler.nodeinfo.Verbosity;
  38 import org.graalvm.compiler.nodes.extended.AnchoringNode;
  39 import org.graalvm.compiler.nodes.extended.GuardingNode;
  40 
  41 import jdk.vm.ci.meta.DeoptimizationAction;
  42 import jdk.vm.ci.meta.DeoptimizationReason;
  43 import jdk.vm.ci.meta.JavaConstant;
  44 
  45 /**
  46  * A guard is a node that deoptimizes based on a conditional expression. Guards are not attached to
  47  * a certain frame state, they can move around freely and will always use the correct frame state
  48  * when the nodes are scheduled (i.e., the last emitted frame state). The node that is guarded has a
  49  * data dependency on the guard and the guard in turn has a data dependency on the condition. A
  50  * guard may only be executed if it is guaranteed that the guarded node is executed too (if no
  51  * exceptions are thrown). Therefore, an anchor is placed after a control flow split and the guard
  52  * has a data dependency to the anchor. The anchor is the most distant node that is post-dominated
  53  * by the guarded node and the guard can be scheduled anywhere between those two nodes. This ensures
  54  * maximum flexibility for the guard node and guarantees that deoptimization occurs only if the
  55  * control flow would have reached the guarded node (without taking exceptions into account).
  56  */
  57 @NodeInfo(nameTemplate = "Guard(!={p#negated}) {p#reason/s}", allowedUsageTypes = {Guard}, size = SIZE_2, cycles = CYCLES_2)
  58 public class GuardNode extends FloatingAnchoredNode implements Canonicalizable, GuardingNode, DeoptimizingGuard, IterableNodeType {
  59 
  60     public static final NodeClass<GuardNode> TYPE = NodeClass.create(GuardNode.class);
  61     @Input(Condition) protected LogicNode condition;
  62     protected final DeoptimizationReason reason;
  63     protected JavaConstant speculation;
  64     protected DeoptimizationAction action;
  65     protected boolean negated;
  66 
  67     public GuardNode(LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated, JavaConstant speculation) {
  68         this(TYPE, condition, anchor, reason, action, negated, speculation);
  69     }
  70 
  71     protected GuardNode(NodeClass<? extends GuardNode> c, LogicNode condition, AnchoringNode anchor, DeoptimizationReason reason, DeoptimizationAction action, boolean negated,
  72                     JavaConstant speculation) {
  73         super(c, StampFactory.forVoid(), anchor);
  74         this.condition = condition;
  75         this.reason = reason;
  76         this.action = action;
  77         this.negated = negated;
  78         this.speculation = speculation;
  79     }
  80 
  81     /**
  82      * The instruction that produces the tested boolean value.
  83      */
  84     @Override
  85     public LogicNode getCondition() {
  86         return condition;
  87     }
  88 
  89     @Override
  90     public void setCondition(LogicNode x, boolean negated) {
  91         updateUsages(condition, x);
  92         condition = x;
  93         this.negated = negated;
  94     }
  95 
  96     @Override
  97     public boolean isNegated() {
  98         return negated;
  99     }
 100 
 101     @Override
 102     public DeoptimizationReason getReason() {
 103         return reason;
 104     }
 105 
 106     @Override
 107     public DeoptimizationAction getAction() {
 108         return action;
 109     }
 110 
 111     @Override
 112     public JavaConstant getSpeculation() {
 113         return speculation;
 114     }
 115 
 116     public void setSpeculation(JavaConstant speculation) {
 117         this.speculation = speculation;
 118     }
 119 
 120     @Override
 121     public String toString(Verbosity verbosity) {
 122         if (verbosity == Verbosity.Name && negated) {
 123             return "!" + super.toString(verbosity);
 124         } else {
 125             return super.toString(verbosity);
 126         }
 127     }
 128 
 129     @Override
 130     public Node canonical(CanonicalizerTool tool) {
 131         if (getCondition() instanceof LogicNegationNode) {
 132             LogicNegationNode negation = (LogicNegationNode) getCondition();
 133             return new GuardNode(negation.getValue(), getAnchor(), reason, action, !negated, speculation);
 134         }
 135         if (getCondition() instanceof LogicConstantNode) {
 136             LogicConstantNode c = (LogicConstantNode) getCondition();
 137             if (c.getValue() != negated) {
 138                 return null;
 139             }
 140         }
 141         return this;
 142     }
 143 
 144     public FixedWithNextNode lowerGuard() {
 145         return null;
 146     }
 147 
 148     public void negate() {
 149         negated = !negated;
 150     }
 151 
 152     public void setAction(DeoptimizationAction invalidaterecompile) {
 153         this.action = invalidaterecompile;
 154     }
 155 }