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 }