1 /* 2 * Copyright (c) 2009, 2016, 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.java; 24 25 import static org.graalvm.compiler.nodeinfo.InputType.Anchor; 26 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_8; 27 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_8; 28 29 import org.graalvm.compiler.core.common.type.ObjectStamp; 30 import org.graalvm.compiler.core.common.type.Stamp; 31 import org.graalvm.compiler.core.common.type.StampFactory; 32 import org.graalvm.compiler.core.common.type.TypeReference; 33 import org.graalvm.compiler.graph.NodeClass; 34 import org.graalvm.compiler.graph.spi.CanonicalizerTool; 35 import org.graalvm.compiler.nodeinfo.NodeInfo; 36 import org.graalvm.compiler.nodes.LogicConstantNode; 37 import org.graalvm.compiler.nodes.LogicNegationNode; 38 import org.graalvm.compiler.nodes.LogicNode; 39 import org.graalvm.compiler.nodes.UnaryOpLogicNode; 40 import org.graalvm.compiler.nodes.ValueNode; 41 import org.graalvm.compiler.nodes.calc.IsNullNode; 42 import org.graalvm.compiler.nodes.extended.AnchoringNode; 43 import org.graalvm.compiler.nodes.spi.Lowerable; 44 import org.graalvm.compiler.nodes.spi.LoweringTool; 45 import org.graalvm.compiler.nodes.spi.Virtualizable; 46 import org.graalvm.compiler.nodes.spi.VirtualizerTool; 47 import org.graalvm.compiler.nodes.type.StampTool; 48 49 import jdk.vm.ci.meta.JavaTypeProfile; 50 import jdk.vm.ci.meta.TriState; 51 52 /** 53 * The {@code InstanceOfNode} represents an instanceof test. 54 */ 55 @NodeInfo(cycles = CYCLES_8, size = SIZE_8) 56 public class InstanceOfNode extends UnaryOpLogicNode implements Lowerable, Virtualizable { 57 public static final NodeClass<InstanceOfNode> TYPE = NodeClass.create(InstanceOfNode.class); 58 59 protected final ObjectStamp checkedStamp; 60 61 private JavaTypeProfile profile; 62 @OptionalInput(Anchor) protected AnchoringNode anchor; 63 64 private InstanceOfNode(ObjectStamp checkedStamp, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) { 65 this(TYPE, checkedStamp, object, profile, anchor); 66 } 67 68 protected InstanceOfNode(NodeClass<? extends InstanceOfNode> c, ObjectStamp checkedStamp, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) { 69 super(c, object); 70 this.checkedStamp = checkedStamp; 71 this.profile = profile; 72 this.anchor = anchor; 73 assert (profile == null) || (anchor != null) : "profiles must be anchored"; 74 assert checkedStamp != null; 75 } 76 77 public static LogicNode createAllowNull(TypeReference type, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) { 78 if (StampTool.isPointerNonNull(object)) { 79 return create(type, object, profile, anchor); 80 } 81 return createHelper(StampFactory.object(type), object, profile, anchor); 82 } 83 84 public static LogicNode create(TypeReference type, ValueNode object) { 85 return create(type, object, null, null); 86 } 87 88 public static LogicNode create(TypeReference type, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) { 89 return createHelper(StampFactory.objectNonNull(type), object, profile, anchor); 90 } 91 92 public static LogicNode createHelper(ObjectStamp checkedStamp, ValueNode object, JavaTypeProfile profile, AnchoringNode anchor) { 93 LogicNode synonym = findSynonym(checkedStamp, object); 94 if (synonym != null) { 95 return synonym; 96 } else { 97 return new InstanceOfNode(checkedStamp, object, profile, anchor); 98 } 99 } 100 101 @Override 102 public void lower(LoweringTool tool) { 103 tool.getLowerer().lower(this, tool); 104 } 105 106 @Override 107 public ValueNode canonical(CanonicalizerTool tool, ValueNode forValue) { 108 LogicNode synonym = findSynonym(checkedStamp, forValue); 109 if (synonym != null) { 110 return synonym; 111 } else { 112 return this; 113 } 114 } 115 116 public static LogicNode findSynonym(ObjectStamp checkedStamp, ValueNode object) { 117 ObjectStamp inputStamp = (ObjectStamp) object.stamp(); 118 ObjectStamp joinedStamp = (ObjectStamp) checkedStamp.join(inputStamp); 119 120 if (joinedStamp.isEmpty()) { 121 // The check can never succeed, the intersection of the two stamps is empty. 122 return LogicConstantNode.contradiction(); 123 } else { 124 ObjectStamp meetStamp = (ObjectStamp) checkedStamp.meet(inputStamp); 125 if (checkedStamp.equals(meetStamp)) { 126 // The check will always succeed, the union of the two stamps is equal to the 127 // checked stamp. 128 return LogicConstantNode.tautology(); 129 } else if (checkedStamp.type().equals(meetStamp.type()) && checkedStamp.isExactType() == meetStamp.isExactType() && checkedStamp.alwaysNull() == meetStamp.alwaysNull()) { 130 assert checkedStamp.nonNull() != inputStamp.nonNull(); 131 // The only difference makes the null-ness of the value => simplify the check. 132 if (checkedStamp.nonNull()) { 133 return LogicNegationNode.create(IsNullNode.create(object)); 134 } else { 135 return IsNullNode.create(object); 136 } 137 } 138 } 139 140 return null; 141 } 142 143 /** 144 * Gets the type being tested. 145 */ 146 public TypeReference type() { 147 return StampTool.typeReferenceOrNull(checkedStamp); 148 } 149 150 public JavaTypeProfile profile() { 151 return profile; 152 } 153 154 @Override 155 public void virtualize(VirtualizerTool tool) { 156 ValueNode alias = tool.getAlias(getValue()); 157 TriState fold = tryFold(alias.stamp()); 158 if (fold != TriState.UNKNOWN) { 159 tool.replaceWithValue(LogicConstantNode.forBoolean(fold.isTrue(), graph())); 160 } 161 } 162 163 @Override 164 public Stamp getSucceedingStampForValue(boolean negated) { 165 if (negated) { 166 return null; 167 } else { 168 return checkedStamp; 169 } 170 } 171 172 @Override 173 public TriState tryFold(Stamp valueStamp) { 174 if (valueStamp instanceof ObjectStamp) { 175 ObjectStamp inputStamp = (ObjectStamp) valueStamp; 176 ObjectStamp joinedStamp = (ObjectStamp) checkedStamp.join(inputStamp); 177 178 if (joinedStamp.isEmpty()) { 179 // The check can never succeed, the intersection of the two stamps is empty. 180 return TriState.FALSE; 181 } else { 182 ObjectStamp meetStamp = (ObjectStamp) checkedStamp.meet(inputStamp); 183 if (checkedStamp.equals(meetStamp)) { 184 // The check will always succeed, the union of the two stamps is equal to the 185 // checked stamp. 186 return TriState.TRUE; 187 } 188 } 189 } 190 return TriState.UNKNOWN; 191 } 192 193 public boolean allowsNull() { 194 return !checkedStamp.nonNull(); 195 } 196 197 public void setProfile(JavaTypeProfile typeProfile, AnchoringNode anchor) { 198 this.profile = typeProfile; 199 updateUsagesInterface(this.anchor, anchor); 200 this.anchor = anchor; 201 assert (profile == null) || (anchor != null) : "profiles must be anchored"; 202 } 203 204 public AnchoringNode getAnchor() { 205 return anchor; 206 } 207 }