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.calc; 26 27 import org.graalvm.compiler.core.common.calc.CanonicalCondition; 28 import org.graalvm.compiler.core.common.type.AbstractPointerStamp; 29 import org.graalvm.compiler.core.common.type.ObjectStamp; 30 import org.graalvm.compiler.core.common.type.Stamp; 31 import org.graalvm.compiler.graph.Node; 32 import org.graalvm.compiler.graph.NodeClass; 33 import org.graalvm.compiler.graph.spi.Canonicalizable.BinaryCommutative; 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.LogicNode; 38 import org.graalvm.compiler.nodes.NodeView; 39 import org.graalvm.compiler.nodes.ValueNode; 40 import org.graalvm.compiler.nodes.extended.LoadHubNode; 41 import org.graalvm.compiler.nodes.extended.LoadMethodNode; 42 import org.graalvm.compiler.nodes.type.StampTool; 43 import org.graalvm.compiler.nodes.util.GraphUtil; 44 import org.graalvm.compiler.options.OptionValues; 45 46 import jdk.vm.ci.meta.ConstantReflectionProvider; 47 import jdk.vm.ci.meta.MetaAccessProvider; 48 import jdk.vm.ci.meta.ResolvedJavaMethod; 49 import jdk.vm.ci.meta.ResolvedJavaType; 50 import jdk.vm.ci.meta.TriState; 51 52 @NodeInfo(shortName = "==") 53 public class PointerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> { 54 55 public static final NodeClass<PointerEqualsNode> TYPE = NodeClass.create(PointerEqualsNode.class); 56 private static final PointerEqualsOp OP = new PointerEqualsOp(); 57 PointerEqualsNode(ValueNode x, ValueNode y)58 public PointerEqualsNode(ValueNode x, ValueNode y) { 59 this(TYPE, x, y); 60 } 61 create(ValueNode x, ValueNode y, NodeView view)62 public static LogicNode create(ValueNode x, ValueNode y, NodeView view) { 63 LogicNode result = findSynonym(x, y, view); 64 if (result != null) { 65 return result; 66 } 67 return new PointerEqualsNode(x, y); 68 } 69 PointerEqualsNode(NodeClass<? extends PointerEqualsNode> c, ValueNode x, ValueNode y)70 protected PointerEqualsNode(NodeClass<? extends PointerEqualsNode> c, ValueNode x, ValueNode y) { 71 super(c, CanonicalCondition.EQ, false, x, y); 72 assert x.stamp(NodeView.DEFAULT).isPointerStamp(); 73 assert y.stamp(NodeView.DEFAULT).isPointerStamp(); 74 } 75 76 @Override canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY)77 public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) { 78 NodeView view = NodeView.from(tool); 79 ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, false, forX, forY, view); 80 if (value != null) { 81 return value; 82 } 83 return this; 84 } 85 86 public static class PointerEqualsOp extends CompareOp { 87 88 /** 89 * Determines if this is a comparison used to determine whether dispatching on a receiver 90 * could select a certain method and if so, returns {@code true} if the answer is guaranteed 91 * to be false. Otherwise, returns {@code false}. 92 */ isAlwaysFailingVirtualDispatchTest(CanonicalCondition condition, ValueNode forX, ValueNode forY)93 private static boolean isAlwaysFailingVirtualDispatchTest(CanonicalCondition condition, ValueNode forX, ValueNode forY) { 94 if (forY.isConstant()) { 95 if (forX instanceof LoadMethodNode && condition == CanonicalCondition.EQ) { 96 LoadMethodNode lm = ((LoadMethodNode) forX); 97 if (lm.getMethod().getEncoding().equals(forY.asConstant())) { 98 if (lm.getHub() instanceof LoadHubNode) { 99 ValueNode object = ((LoadHubNode) lm.getHub()).getValue(); 100 ResolvedJavaType type = StampTool.typeOrNull(object); 101 ResolvedJavaType declaringClass = lm.getMethod().getDeclaringClass(); 102 if (type != null && !type.equals(declaringClass) && declaringClass.isAssignableFrom(type)) { 103 ResolvedJavaMethod override = type.resolveMethod(lm.getMethod(), lm.getCallerType()); 104 if (override != null && !override.equals(lm.getMethod())) { 105 assert declaringClass.isAssignableFrom(override.getDeclaringClass()); 106 return true; 107 } 108 } 109 } 110 } 111 } 112 } 113 return false; 114 } 115 116 @Override canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view)117 public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition, 118 boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) { 119 LogicNode result = findSynonym(forX, forY, view); 120 if (result != null) { 121 return result; 122 } 123 if (isAlwaysFailingVirtualDispatchTest(condition, forX, forY)) { 124 return LogicConstantNode.contradiction(); 125 } 126 return super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view); 127 } 128 129 @Override duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue, NodeView view)130 protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue, NodeView view) { 131 return new PointerEqualsNode(newX, newY); 132 } 133 } 134 findSynonym(ValueNode forX, ValueNode forY, NodeView view)135 public static LogicNode findSynonym(ValueNode forX, ValueNode forY, NodeView view) { 136 if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) { 137 return LogicConstantNode.tautology(); 138 } else if (forX.stamp(view).alwaysDistinct(forY.stamp(view))) { 139 return LogicConstantNode.contradiction(); 140 } else if (forX.stamp(view) instanceof AbstractPointerStamp && ((AbstractPointerStamp) forX.stamp(view)).alwaysNull()) { 141 return nullSynonym(forY, forX); 142 } else if (forY.stamp(view) instanceof AbstractPointerStamp && ((AbstractPointerStamp) forY.stamp(view)).alwaysNull()) { 143 return nullSynonym(forX, forY); 144 } else { 145 return null; 146 } 147 } 148 nullSynonym(ValueNode nonNullValue, ValueNode nullValue)149 private static LogicNode nullSynonym(ValueNode nonNullValue, ValueNode nullValue) { 150 if (nullValue.isConstant()) { 151 return IsNullNode.create(nonNullValue, nullValue.asJavaConstant()); 152 } else { 153 return IsNullNode.create(nonNullValue); 154 } 155 } 156 157 @Override getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp)158 public Stamp getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp) { 159 if (!negated) { 160 Stamp newStamp = xStamp.join(yStamp); 161 if (!newStamp.equals(xStamp)) { 162 return newStamp; 163 } 164 } 165 return null; 166 } 167 168 @Override getSucceedingStampForY(boolean negated, Stamp xStamp, Stamp yStamp)169 public Stamp getSucceedingStampForY(boolean negated, Stamp xStamp, Stamp yStamp) { 170 if (!negated) { 171 Stamp newStamp = yStamp.join(xStamp); 172 if (!newStamp.equals(yStamp)) { 173 return newStamp; 174 } 175 } 176 return null; 177 } 178 179 @Override tryFold(Stamp xStampGeneric, Stamp yStampGeneric)180 public TriState tryFold(Stamp xStampGeneric, Stamp yStampGeneric) { 181 if (xStampGeneric instanceof ObjectStamp && yStampGeneric instanceof ObjectStamp) { 182 ObjectStamp xStamp = (ObjectStamp) xStampGeneric; 183 ObjectStamp yStamp = (ObjectStamp) yStampGeneric; 184 if (xStamp.alwaysDistinct(yStamp)) { 185 return TriState.FALSE; 186 } else if (xStamp.neverDistinct(yStamp)) { 187 return TriState.TRUE; 188 } 189 } 190 return TriState.UNKNOWN; 191 } 192 } 193