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 }