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