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