1 /*
   2  * Copyright (c) 2011, 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.core.common.type;
  24 
  25 import static jdk.vm.ci.code.CodeUtil.signExtend;
  26 
  27 import org.graalvm.compiler.core.common.NumUtil;
  28 import org.graalvm.compiler.debug.GraalError;
  29 
  30 import jdk.vm.ci.code.CodeUtil;
  31 import jdk.vm.ci.meta.Assumptions;
  32 import jdk.vm.ci.meta.JavaConstant;
  33 import jdk.vm.ci.meta.JavaKind;
  34 import jdk.vm.ci.meta.JavaType;
  35 import jdk.vm.ci.meta.MetaAccessProvider;
  36 import jdk.vm.ci.meta.ResolvedJavaMethod;
  37 import jdk.vm.ci.meta.ResolvedJavaType;
  38 import jdk.vm.ci.meta.Signature;
  39 
  40 public class StampFactory {
  41 
  42     /*
  43      * The marker stamp for node intrinsics must be its own class, so that it is never equal() to a
  44      * regular ObjectStamp.
  45      */
  46     static final class NodeIntrinsicStamp extends ObjectStamp {
  47         protected static final Stamp SINGLETON = new NodeIntrinsicStamp();
  48 
  49         private NodeIntrinsicStamp() {
  50             super(null, false, false, false);
  51         }
  52 
  53         @Override
  54         public int hashCode() {
  55             return System.identityHashCode(this);
  56         }
  57 
  58         @Override
  59         public boolean equals(Object obj) {
  60             return this == obj;
  61         }
  62 
  63         @Override
  64         public String toString() {
  65             return "NodeIntrinsicStamp";
  66         }
  67     }
  68 
  69     // JaCoCo Exclude
  70 
  71     private static final Stamp[] stampCache = new Stamp[JavaKind.values().length];
  72     private static final Stamp[] emptyStampCache = new Stamp[JavaKind.values().length];
  73     private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
  74     private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
  75     private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
  76     private static final Stamp positiveInt = forInteger(JavaKind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
  77     private static final Stamp booleanTrue = forInteger(JavaKind.Boolean, -1, -1, 1, 1);
  78     private static final Stamp booleanFalse = forInteger(JavaKind.Boolean, 0, 0, 0, 0);
  79     private static final Stamp rawPointer = new RawPointerStamp();
  80 
  81     private static void setCache(JavaKind kind, Stamp stamp) {
  82         stampCache[kind.ordinal()] = stamp;
  83     }
  84 
  85     private static void setIntCache(JavaKind kind) {
  86         int bits = kind.getStackKind().getBitCount();
  87         long mask;
  88         if (kind.isUnsigned()) {
  89             mask = CodeUtil.mask(kind.getBitCount());
  90         } else {
  91             mask = CodeUtil.mask(bits);
  92         }
  93         setCache(kind, IntegerStamp.create(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
  94     }
  95 
  96     private static void setFloatCache(JavaKind kind) {
  97         setCache(kind, new FloatStamp(kind.getBitCount()));
  98     }
  99 
 100     static {
 101         setIntCache(JavaKind.Boolean);
 102         setIntCache(JavaKind.Byte);
 103         setIntCache(JavaKind.Short);
 104         setIntCache(JavaKind.Char);
 105         setIntCache(JavaKind.Int);
 106         setIntCache(JavaKind.Long);
 107 
 108         setFloatCache(JavaKind.Float);
 109         setFloatCache(JavaKind.Double);
 110 
 111         setCache(JavaKind.Object, objectStamp);
 112         setCache(JavaKind.Void, VoidStamp.getInstance());
 113         setCache(JavaKind.Illegal, IllegalStamp.getInstance());
 114 
 115         for (JavaKind k : JavaKind.values()) {
 116             if (stampCache[k.ordinal()] != null) {
 117                 emptyStampCache[k.ordinal()] = stampCache[k.ordinal()].empty();
 118             }
 119         }
 120     }
 121 
 122     public static Stamp tautology() {
 123         return booleanTrue;
 124     }
 125 
 126     public static Stamp contradiction() {
 127         return booleanFalse;
 128     }
 129 
 130     /**
 131      * Return a stamp for a Java kind, as it would be represented on the bytecode stack.
 132      */
 133     public static Stamp forKind(JavaKind kind) {
 134         assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")";
 135         return stampCache[kind.ordinal()];
 136     }
 137 
 138     /**
 139      * Return the stamp for the {@code void} type. This will return a singleton instance than can be
 140      * compared using {@code ==}.
 141      */
 142     public static Stamp forVoid() {
 143         return VoidStamp.getInstance();
 144     }
 145 
 146     /**
 147      * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an
 148      * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated.
 149      */
 150     public static Stamp forNodeIntrinsic() {
 151         return NodeIntrinsicStamp.SINGLETON;
 152     }
 153 
 154     public static Stamp intValue() {
 155         return forKind(JavaKind.Int);
 156     }
 157 
 158     public static Stamp positiveInt() {
 159         return positiveInt;
 160     }
 161 
 162     public static Stamp empty(JavaKind kind) {
 163         return emptyStampCache[kind.ordinal()];
 164     }
 165 
 166     public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) {
 167         return IntegerStamp.create(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
 168     }
 169 
 170     public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) {
 171         return forInteger(kind.getBitCount(), lowerBound, upperBound);
 172     }
 173 
 174     /**
 175      * Create a new stamp use {@code newLowerBound} and {@code newUpperBound} computing the
 176      * appropriate {@link IntegerStamp#upMask} and {@link IntegerStamp#downMask} and incorporating
 177      * any mask information from {@code maskStamp}.
 178      *
 179      * @param bits
 180      * @param newLowerBound
 181      * @param newUpperBound
 182      * @param maskStamp
 183      * @return a new stamp with the appropriate bounds and masks
 184      */
 185     public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) {
 186         IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
 187         return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
 188     }
 189 
 190     public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) {
 191         IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
 192         return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
 193     }
 194 
 195     public static IntegerStamp forInteger(int bits) {
 196         return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
 197     }
 198 
 199     public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) {
 200         return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits));
 201     }
 202 
 203     public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound, long downMask, long upMask) {
 204         long lowerBound = signExtend(unsignedLowerBound, bits);
 205         long upperBound = signExtend(unsignedUpperBound, bits);
 206         if (!NumUtil.sameSign(lowerBound, upperBound)) {
 207             lowerBound = CodeUtil.minValue(bits);
 208             upperBound = CodeUtil.maxValue(bits);
 209         }
 210         long mask = CodeUtil.mask(bits);
 211         return IntegerStamp.create(bits, lowerBound, upperBound, downMask & mask, upMask & mask);
 212     }
 213 
 214     public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
 215         return IntegerStamp.create(bits, lowerBound, upperBound, 0, CodeUtil.mask(bits));
 216     }
 217 
 218     public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) {
 219         assert kind.isNumericFloat();
 220         return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN);
 221     }
 222 
 223     public static Stamp forConstant(JavaConstant value) {
 224         JavaKind kind = value.getJavaKind();
 225         switch (kind) {
 226             case Boolean:
 227             case Byte:
 228             case Char:
 229             case Short:
 230             case Int:
 231             case Long:
 232                 long mask = value.asLong() & CodeUtil.mask(kind.getBitCount());
 233                 return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask);
 234             case Float:
 235                 return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
 236             case Double:
 237                 return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
 238             case Illegal:
 239                 return forKind(JavaKind.Illegal);
 240             case Object:
 241                 if (value.isNull()) {
 242                     return alwaysNull();
 243                 } else {
 244                     return objectNonNull();
 245                 }
 246             default:
 247                 throw new GraalError("unexpected kind: %s", kind);
 248         }
 249     }
 250 
 251     public static Stamp forConstant(JavaConstant value, MetaAccessProvider metaAccess) {
 252         if (value.getJavaKind() == JavaKind.Object) {
 253             ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value);
 254             return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
 255         } else {
 256             return forConstant(value);
 257         }
 258     }
 259 
 260     public static Stamp object() {
 261         return objectStamp;
 262     }
 263 
 264     public static Stamp objectNonNull() {
 265         return objectNonNullStamp;
 266     }
 267 
 268     public static Stamp alwaysNull() {
 269         return objectAlwaysNullStamp;
 270     }
 271 
 272     public static ObjectStamp object(TypeReference type) {
 273         return object(type, false);
 274     }
 275 
 276     public static ObjectStamp objectNonNull(TypeReference type) {
 277         return object(type, true);
 278     }
 279 
 280     public static ObjectStamp object(TypeReference type, boolean nonNull) {
 281         if (type == null) {
 282             return new ObjectStamp(null, false, nonNull, false);
 283         } else {
 284             return new ObjectStamp(type.getType(), type.isExact(), nonNull, false);
 285         }
 286     }
 287 
 288     public static Stamp[] createParameterStamps(Assumptions assumptions, ResolvedJavaMethod method) {
 289         Signature sig = method.getSignature();
 290         Stamp[] result = new Stamp[sig.getParameterCount(!method.isStatic())];
 291         int index = 0;
 292 
 293         if (!method.isStatic()) {
 294             result[index++] = StampFactory.objectNonNull(TypeReference.create(assumptions, method.getDeclaringClass()));
 295         }
 296 
 297         int max = sig.getParameterCount(false);
 298         ResolvedJavaType accessingClass = method.getDeclaringClass();
 299         for (int i = 0; i < max; i++) {
 300             JavaType type = sig.getParameterType(i, accessingClass);
 301             JavaKind kind = type.getJavaKind();
 302             Stamp stamp;
 303             if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
 304                 stamp = StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) type));
 305             } else {
 306                 stamp = StampFactory.forKind(kind);
 307             }
 308             result[index++] = stamp;
 309         }
 310 
 311         return result;
 312     }
 313 
 314     public static Stamp pointer() {
 315         return rawPointer;
 316     }
 317 
 318     public static StampPair forDeclaredType(Assumptions assumptions, JavaType returnType, boolean nonNull) {
 319         if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) {
 320             ResolvedJavaType resolvedJavaType = (ResolvedJavaType) returnType;
 321             TypeReference reference = TypeReference.create(assumptions, resolvedJavaType);
 322             if (resolvedJavaType.isInterface()) {
 323                 ResolvedJavaType implementor = resolvedJavaType.getSingleImplementor();
 324                 if (implementor != null && !resolvedJavaType.equals(implementor)) {
 325                     TypeReference uncheckedType = TypeReference.createTrusted(assumptions, implementor);
 326                     return StampPair.create(StampFactory.object(reference, nonNull), StampFactory.object(uncheckedType, nonNull));
 327                 }
 328             }
 329             return StampPair.createSingle(StampFactory.object(reference, nonNull));
 330         } else {
 331             return StampPair.createSingle(StampFactory.forKind(returnType.getJavaKind()));
 332         }
 333     }
 334 }