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.NodeCycles.CYCLES_30;
  26 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_30;
  27 
  28 import org.graalvm.compiler.core.common.type.Stamp;
  29 import org.graalvm.compiler.core.common.type.TypeReference;
  30 import org.graalvm.compiler.graph.NodeClass;
  31 import org.graalvm.compiler.graph.spi.Canonicalizable;
  32 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
  33 import org.graalvm.compiler.nodeinfo.NodeInfo;
  34 import org.graalvm.compiler.nodes.BinaryOpLogicNode;
  35 import org.graalvm.compiler.nodes.LogicConstantNode;
  36 import org.graalvm.compiler.nodes.LogicNode;
  37 import org.graalvm.compiler.nodes.ValueNode;
  38 import org.graalvm.compiler.nodes.calc.IsNullNode;
  39 import org.graalvm.compiler.nodes.spi.Lowerable;
  40 import org.graalvm.compiler.nodes.spi.LoweringTool;
  41 
  42 import jdk.vm.ci.meta.Assumptions;
  43 import jdk.vm.ci.meta.ConstantReflectionProvider;
  44 import jdk.vm.ci.meta.JavaKind;
  45 import jdk.vm.ci.meta.ResolvedJavaType;
  46 import jdk.vm.ci.meta.TriState;
  47 
  48 /**
  49  * The {@code InstanceOfDynamicNode} represents a type check where the type being checked is not
  50  * known at compile time. This is used, for instance, to intrinsify {@link Class#isInstance(Object)}
  51  * .
  52  */
  53 @NodeInfo(cycles = CYCLES_30, size = SIZE_30)
  54 public class InstanceOfDynamicNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode>, Lowerable {
  55     public static final NodeClass<InstanceOfDynamicNode> TYPE = NodeClass.create(InstanceOfDynamicNode.class);
  56 
  57     private final boolean allowNull;
  58 
  59     public static LogicNode create(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode mirror, ValueNode object, boolean allowNull) {
  60         LogicNode synonym = findSynonym(assumptions, constantReflection, mirror, object, allowNull);
  61         if (synonym != null) {
  62             return synonym;
  63         }
  64         return new InstanceOfDynamicNode(mirror, object, allowNull);
  65     }
  66 
  67     protected InstanceOfDynamicNode(ValueNode mirror, ValueNode object, boolean allowNull) {
  68         super(TYPE, mirror, object);
  69         this.allowNull = allowNull;
  70         assert mirror.getStackKind() == JavaKind.Object || mirror.getStackKind() == JavaKind.Illegal : mirror.getStackKind();
  71     }
  72 
  73     public boolean isMirror() {
  74         return getMirrorOrHub().getStackKind() == JavaKind.Object;
  75     }
  76 
  77     public boolean isHub() {
  78         return !isMirror();
  79     }
  80 
  81     @Override
  82     public void lower(LoweringTool tool) {
  83         tool.getLowerer().lower(this, tool);
  84     }
  85 
  86     private static LogicNode findSynonym(Assumptions assumptions, ConstantReflectionProvider constantReflection, ValueNode forMirror, ValueNode forObject,
  87                     boolean allowNull) {
  88         if (forMirror.isConstant()) {
  89             ResolvedJavaType t = constantReflection.asJavaType(forMirror.asConstant());
  90             if (t != null) {
  91                 if (t.isPrimitive()) {
  92                     if (allowNull) {
  93                         return IsNullNode.create(forObject);
  94                     } else {
  95                         return LogicConstantNode.contradiction();
  96                     }
  97                 } else {
  98                     TypeReference type = TypeReference.createTrusted(assumptions, t);
  99                     if (allowNull) {
 100                         return InstanceOfNode.createAllowNull(type, forObject, null, null);
 101                     } else {
 102                         return InstanceOfNode.create(type, forObject);
 103                     }
 104                 }
 105             }
 106         }
 107         return null;
 108     }
 109 
 110     public ValueNode getMirrorOrHub() {
 111         return this.getX();
 112     }
 113 
 114     public ValueNode getObject() {
 115         return this.getY();
 116     }
 117 
 118     @Override
 119     public LogicNode canonical(CanonicalizerTool tool, ValueNode forMirror, ValueNode forObject) {
 120         LogicNode result = findSynonym(tool.getAssumptions(), tool.getConstantReflection(), forMirror, forObject, allowNull);
 121         if (result != null) {
 122             return result;
 123         }
 124         return this;
 125     }
 126 
 127     public void setMirror(ValueNode newObject) {
 128         this.updateUsages(x, newObject);
 129         this.x = newObject;
 130     }
 131 
 132     public boolean allowsNull() {
 133         return allowNull;
 134     }
 135 
 136     @Override
 137     public Stamp getSucceedingStampForX(boolean negated, Stamp xStamp, Stamp yStamp) {
 138         return null;
 139     }
 140 
 141     @Override
 142     public Stamp getSucceedingStampForY(boolean negated, Stamp xStamp, Stamp yStamp) {
 143         return null;
 144     }
 145 
 146     @Override
 147     public TriState tryFold(Stamp xStamp, Stamp yStamp) {
 148         return TriState.UNKNOWN;
 149     }
 150 }