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 }