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