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