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 58 public PointerEqualsNode(ValueNode x, ValueNode y) { 59 this(TYPE, x, y); 60 } 61 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 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) instanceof AbstractPointerStamp; 73 assert y.stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp; 74 } 75 76 @Override 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 */ 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 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 130 protected CompareNode duplicateModified(ValueNode newX, ValueNode newY, boolean unorderedIsTrue, NodeView view) { 131 return new PointerEqualsNode(newX, newY); 132 } 133 } 134 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 (((AbstractPointerStamp) forX.stamp(view)).alwaysNull()) { 141 return nullSynonym(forY, forX); 142 } else if (((AbstractPointerStamp) forY.stamp(view)).alwaysNull()) { 143 return nullSynonym(forX, forY); 144 } else { 145 return null; 146 } 147 } 148 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 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 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 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 }