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 }