1 /*
   2  * Copyright (c) 2011, 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.nodes;
  26 
  27 import static org.graalvm.compiler.nodeinfo.InputType.Guard;
  28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
  29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
  30 
  31 import org.graalvm.compiler.debug.DebugCloseable;
  32 import org.graalvm.compiler.graph.IterableNodeType;
  33 import org.graalvm.compiler.graph.Node;
  34 import org.graalvm.compiler.graph.NodeClass;
  35 import org.graalvm.compiler.graph.NodeSourcePosition;
  36 import org.graalvm.compiler.graph.spi.SimplifierTool;
  37 import org.graalvm.compiler.nodeinfo.NodeInfo;
  38 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
  39 import org.graalvm.compiler.nodes.spi.Lowerable;
  40 import org.graalvm.compiler.nodes.spi.LoweringTool;
  41 import org.graalvm.compiler.nodes.spi.SwitchFoldable;
  42 
  43 import jdk.vm.ci.meta.DeoptimizationAction;
  44 import jdk.vm.ci.meta.DeoptimizationReason;
  45 import jdk.vm.ci.meta.SpeculationLog;
  46 
  47 @NodeInfo(nameTemplate = "FixedGuard(!={p#negated}) {p#reason/s}", allowedUsageTypes = Guard, size = SIZE_2, cycles = CYCLES_2)
  48 public final class FixedGuardNode extends AbstractFixedGuardNode implements Lowerable, IterableNodeType, SwitchFoldable {
  49     public static final NodeClass<FixedGuardNode> TYPE = NodeClass.create(FixedGuardNode.class);
  50 
  51     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action) {
  52         this(condition, deoptReason, action, SpeculationLog.NO_SPECULATION, false);
  53     }
  54 
  55     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated) {
  56         this(condition, deoptReason, action, SpeculationLog.NO_SPECULATION, negated);
  57     }
  58 
  59     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, boolean negated, NodeSourcePosition noDeoptSuccessorPosition) {
  60         this(condition, deoptReason, action, SpeculationLog.NO_SPECULATION, negated, noDeoptSuccessorPosition);
  61     }
  62 
  63     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, SpeculationLog.Speculation speculation, boolean negated) {
  64         super(TYPE, condition, deoptReason, action, speculation, negated);
  65     }
  66 
  67     public FixedGuardNode(LogicNode condition, DeoptimizationReason deoptReason, DeoptimizationAction action, SpeculationLog.Speculation speculation, boolean negated,
  68                     NodeSourcePosition noDeoptSuccessorPosition) {
  69         super(TYPE, condition, deoptReason, action, speculation, negated, noDeoptSuccessorPosition);
  70     }
  71 
  72     @Override
  73     public void simplify(SimplifierTool tool) {
  74         super.simplify(tool);
  75 
  76         if (getCondition() instanceof LogicConstantNode) {
  77             LogicConstantNode c = (LogicConstantNode) getCondition();
  78             if (c.getValue() == isNegated()) {
  79                 FixedNode currentNext = this.next();
  80                 if (currentNext != null) {
  81                     tool.deleteBranch(currentNext);
  82                 }
  83 
  84                 DeoptimizeNode deopt = graph().add(new DeoptimizeNode(getAction(), getReason(), getSpeculation()));
  85                 deopt.setStateBefore(stateBefore());
  86                 setNext(deopt);
  87             }
  88             this.replaceAtUsages(null);
  89             graph().removeFixed(this);
  90         } else if (getCondition() instanceof ShortCircuitOrNode) {
  91             ShortCircuitOrNode shortCircuitOr = (ShortCircuitOrNode) getCondition();
  92             if (isNegated() && hasNoUsages()) {
  93                 graph().addAfterFixed(this,
  94                                 graph().add(new FixedGuardNode(shortCircuitOr.getY(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isYNegated(), getNoDeoptSuccessorPosition())));
  95                 graph().replaceFixedWithFixed(this,
  96                                 graph().add(new FixedGuardNode(shortCircuitOr.getX(), getReason(), getAction(), getSpeculation(), !shortCircuitOr.isXNegated(), getNoDeoptSuccessorPosition())));
  97             }
  98         }
  99     }
 100 
 101     @SuppressWarnings("try")
 102     @Override
 103     public void lower(LoweringTool tool) {
 104         try (DebugCloseable position = this.withNodeSourcePosition()) {
 105             if (graph().getGuardsStage().allowsFloatingGuards()) {
 106                 if (getAction() != DeoptimizationAction.None) {
 107                     ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated(), getNoDeoptSuccessorPosition()).asNode();
 108                     this.replaceAtUsages(guard);
 109                     graph().removeFixed(this);
 110                 }
 111             } else {
 112                 lowerToIf().lower(tool);
 113             }
 114         }
 115     }
 116 
 117     @Override
 118     public boolean canDeoptimize() {
 119         return true;
 120     }
 121 
 122     @Override
 123     public Node getNextSwitchFoldableBranch() {
 124         return next();
 125     }
 126 
 127     @Override
 128     public boolean isInSwitch(ValueNode switchValue) {
 129         return hasNoUsages() && isNegated() && SwitchFoldable.maybeIsInSwitch(condition()) && SwitchFoldable.sameSwitchValue(condition(), switchValue);
 130     }
 131 
 132     @Override
 133     public void cutOffCascadeNode() {
 134         /* nop */
 135     }
 136 
 137     @Override
 138     public void cutOffLowestCascadeNode() {
 139         setNext(null);
 140     }
 141 
 142     @Override
 143     public boolean isDefaultSuccessor(AbstractBeginNode beginNode) {
 144         return beginNode.next() == next();
 145     }
 146 
 147     @Override
 148     public AbstractBeginNode getDefault() {
 149         FixedNode defaultNode = next();
 150         setNext(null);
 151         return BeginNode.begin(defaultNode);
 152     }
 153 
 154     @Override
 155     public ValueNode switchValue() {
 156         if (SwitchFoldable.maybeIsInSwitch(condition())) {
 157             return ((IntegerEqualsNode) condition()).getX();
 158         }
 159         return null;
 160     }
 161 
 162     @Override
 163     public boolean isNonInitializedProfile() {
 164         // @formatter:off
 165         // Checkstyle: stop
 166         /*
 167          * These nodes can appear in non initialized cascades. Though they are technically profiled
 168          * nodes, their presence does not really prevent us from constructing a uniform distribution
 169          * for the new switch, while keeping these to probability 0. Furthermore, these can be the
 170          * result of the pattern: 
 171          * if (c) {
 172          *     CompilerDirectives.transferToInterpreter();
 173          * } 
 174          * Since we cannot differentiate this case from, say, a guard created because profiling 
 175          * determined that the branch was never taken, and given what we saw before, we will 
 176          * consider all fixedGuards as nodes with no profiles for switch folding purposes.
 177          */
 178         // Checkstyle: resume
 179         // @formatter:on
 180         return true;
 181     }
 182 
 183     @Override
 184     public int intKeyAt(int i) {
 185         assert i == 0;
 186         return ((IntegerEqualsNode) condition()).getY().asJavaConstant().asInt();
 187     }
 188 
 189     @Override
 190     public double keyProbability(int i) {
 191         return 0;
 192     }
 193 
 194     @Override
 195     public AbstractBeginNode keySuccessor(int i) {
 196         DeoptimizeNode deopt = new DeoptimizeNode(getAction(), getReason(), getSpeculation());
 197         deopt.setNodeSourcePosition(getNodeSourcePosition());
 198         AbstractBeginNode begin = new BeginNode();
 199         // Link the two nodes, but do not add them to the graph yet, so we do not need to remove
 200         // them on an abort.
 201         begin.next = deopt;
 202         return begin;
 203     }
 204 
 205     @Override
 206     public double defaultProbability() {
 207         return 1.0d;
 208     }
 209 }