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