001/* 002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.compiler.common.type; 024 025import jdk.internal.jvmci.code.*; 026import jdk.internal.jvmci.common.*; 027import jdk.internal.jvmci.meta.*; 028 029public class StampFactory { 030 031 // JaCoCo Exclude 032 033 private static final Stamp[] stampCache = new Stamp[Kind.values().length]; 034 private static final Stamp[] emptyStampCache = new Stamp[Kind.values().length]; 035 private static final Stamp objectStamp = new ObjectStamp(null, false, false, false); 036 private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false); 037 private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true); 038 private static final Stamp nodeIntrinsicStamp = new ObjectStamp(null, false, false, false); 039 private static final Stamp positiveInt = forInteger(Kind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE); 040 private static final Stamp booleanTrue = forInteger(Kind.Boolean, -1, -1, 1, 1); 041 private static final Stamp booleanFalse = forInteger(Kind.Boolean, 0, 0, 0, 0); 042 private static final Stamp rawPointer = new RawPointerStamp(); 043 044 private static void setCache(Kind kind, Stamp stamp) { 045 stampCache[kind.ordinal()] = stamp; 046 } 047 048 private static void setIntCache(Kind kind) { 049 int bits = kind.getStackKind().getBitCount(); 050 long mask; 051 if (kind.isUnsigned()) { 052 mask = CodeUtil.mask(kind.getBitCount()); 053 } else { 054 mask = CodeUtil.mask(bits); 055 } 056 setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask)); 057 } 058 059 private static void setFloatCache(Kind kind) { 060 setCache(kind, new FloatStamp(kind.getBitCount())); 061 } 062 063 static { 064 setIntCache(Kind.Boolean); 065 setIntCache(Kind.Byte); 066 setIntCache(Kind.Short); 067 setIntCache(Kind.Char); 068 setIntCache(Kind.Int); 069 setIntCache(Kind.Long); 070 071 setFloatCache(Kind.Float); 072 setFloatCache(Kind.Double); 073 074 setCache(Kind.Object, objectStamp); 075 setCache(Kind.Void, VoidStamp.getInstance()); 076 setCache(Kind.Illegal, IllegalStamp.getInstance()); 077 078 for (Kind k : Kind.values()) { 079 if (stampCache[k.ordinal()] != null) { 080 emptyStampCache[k.ordinal()] = stampCache[k.ordinal()].empty(); 081 } 082 } 083 } 084 085 public static Stamp tautology() { 086 return booleanTrue; 087 } 088 089 public static Stamp contradiction() { 090 return booleanFalse; 091 } 092 093 /** 094 * Return a stamp for a Java kind, as it would be represented on the bytecode stack. 095 */ 096 public static Stamp forKind(Kind kind) { 097 assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")"; 098 return stampCache[kind.ordinal()]; 099 } 100 101 /** 102 * Return the stamp for the {@code void} type. This will return a singleton instance than can be 103 * compared using {@code ==}. 104 */ 105 public static Stamp forVoid() { 106 return VoidStamp.getInstance(); 107 } 108 109 /** 110 * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an 111 * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated. 112 */ 113 public static Stamp forNodeIntrinsic() { 114 return nodeIntrinsicStamp; 115 } 116 117 public static Stamp intValue() { 118 return forKind(Kind.Int); 119 } 120 121 public static Stamp positiveInt() { 122 return positiveInt; 123 } 124 125 public static Stamp empty(Kind kind) { 126 return emptyStampCache[kind.ordinal()]; 127 } 128 129 public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound, long downMask, long upMask) { 130 return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask); 131 } 132 133 public static IntegerStamp forInteger(Kind kind, long lowerBound, long upperBound) { 134 return forInteger(kind.getBitCount(), lowerBound, upperBound); 135 } 136 137 public static IntegerStamp forInteger(int bits) { 138 return new IntegerStamp(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits)); 139 } 140 141 public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) { 142 long defaultMask = CodeUtil.mask(bits); 143 if (lowerBound == upperBound) { 144 return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask); 145 } 146 final long downMask; 147 final long upMask; 148 if (lowerBound >= 0) { 149 int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound); 150 long differentBits = lowerBound ^ upperBound; 151 int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros); 152 153 upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount); 154 downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount)); 155 } else { 156 if (upperBound >= 0) { 157 upMask = defaultMask; 158 downMask = 0; 159 } else { 160 int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound); 161 long differentBits = lowerBound ^ upperBound; 162 int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes); 163 164 upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes); 165 downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes); 166 } 167 } 168 return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask); 169 } 170 171 public static FloatStamp forFloat(Kind kind, double lowerBound, double upperBound, boolean nonNaN) { 172 assert kind.isNumericFloat(); 173 return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN); 174 } 175 176 public static Stamp forConstant(JavaConstant value) { 177 Kind kind = value.getKind(); 178 switch (kind) { 179 case Boolean: 180 case Byte: 181 case Char: 182 case Short: 183 case Int: 184 case Long: 185 long mask = value.asLong() & CodeUtil.mask(kind.getBitCount()); 186 return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask); 187 case Float: 188 return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat())); 189 case Double: 190 return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble())); 191 case Illegal: 192 return forKind(Kind.Illegal); 193 case Object: 194 if (value.isNull()) { 195 return alwaysNull(); 196 } else { 197 return objectNonNull(); 198 } 199 default: 200 throw new JVMCIError("unexpected kind: %s", kind); 201 } 202 } 203 204 public static Stamp forConstant(JavaConstant value, MetaAccessProvider metaAccess) { 205 if (value.getKind() == Kind.Object) { 206 ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value); 207 return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull()); 208 } else { 209 return forConstant(value); 210 } 211 } 212 213 public static Stamp object() { 214 return objectStamp; 215 } 216 217 public static Stamp objectNonNull() { 218 return objectNonNullStamp; 219 } 220 221 public static Stamp alwaysNull() { 222 return objectAlwaysNullStamp; 223 } 224 225 /** 226 * Returns a {@link Stamp} for objects of type {@code type}, or one of its subtypes, or null. 227 */ 228 public static Stamp declared(ResolvedJavaType type) { 229 return object(type, false, false, false); 230 } 231 232 /** 233 * Returns a {@link Stamp} for objects of type {@code type}, or one of its subtypes, but not 234 * null. 235 */ 236 public static Stamp declaredNonNull(ResolvedJavaType type) { 237 return object(type, false, true, false); 238 } 239 240 /** 241 * Returns a {@link Stamp} for objects of type {@code type}, or one of its subtypes, or null. 242 * Contrary to {@link #declared(ResolvedJavaType)}, interface types will be preserved in the 243 * stamp. 244 * 245 * In general interface types are not verified at class loading or run-time so this should be 246 * used with care. 247 */ 248 public static Stamp declaredTrusted(ResolvedJavaType type) { 249 return object(type, false, false, true); 250 } 251 252 /** 253 * Returns a {@link Stamp} for objects of type {@code type}, or one of its subtypes, but not 254 * null. Contrary to {@link #declaredNonNull(ResolvedJavaType)}, interface types will be 255 * preserved in the stamp. 256 * 257 * In general interface types are not verified at class loading or run-time so this should be 258 * used with care. 259 */ 260 public static Stamp declaredTrustedNonNull(ResolvedJavaType type) { 261 return declaredTrusted(type, true); 262 } 263 264 public static Stamp declaredTrusted(ResolvedJavaType type, boolean nonNull) { 265 return object(type, false, nonNull, true); 266 } 267 268 /** 269 * Returns a {@link Stamp} for objects of exactly type {@code type}, or null. 270 */ 271 public static Stamp exact(ResolvedJavaType type) { 272 if (ObjectStamp.isConcreteType(type)) { 273 return new ObjectStamp(type, true, false, false); 274 } else { 275 return empty(Kind.Object); 276 } 277 } 278 279 /** 280 * Returns a {@link Stamp} for non-null objects of exactly type {@code type}. 281 */ 282 public static Stamp exactNonNull(ResolvedJavaType type) { 283 if (ObjectStamp.isConcreteType(type)) { 284 return new ObjectStamp(type, true, true, false); 285 } else { 286 return empty(Kind.Object); 287 } 288 } 289 290 private static ResolvedJavaType filterInterfaceTypesOut(ResolvedJavaType type) { 291 if (type.isArray()) { 292 ResolvedJavaType componentType = filterInterfaceTypesOut(type.getComponentType()); 293 if (componentType != null) { 294 return componentType.getArrayClass(); 295 } 296 return type.getSuperclass().getArrayClass(); // arrayType.getSuperClass() == Object type 297 } 298 if (type.isInterface() && !type.isTrustedInterfaceType()) { 299 return null; 300 } 301 return type; 302 } 303 304 public static Stamp object(ResolvedJavaType type, boolean exactType, boolean nonNull, boolean trustInterfaces) { 305 assert type != null; 306 assert type.getKind() == Kind.Object; 307 ResolvedJavaType trustedtype; 308 if (!trustInterfaces) { 309 trustedtype = filterInterfaceTypesOut(type); 310 assert !exactType || trustedtype.equals(type); 311 } else { 312 trustedtype = type; 313 } 314 ResolvedJavaType exact = trustedtype != null ? trustedtype.asExactType() : null; 315 if (exact != null) { 316 assert !exactType || trustedtype.equals(exact); 317 return new ObjectStamp(exact, true, nonNull, false); 318 } 319 assert !exactType || AbstractObjectStamp.isConcreteType(trustedtype); 320 return new ObjectStamp(trustedtype, exactType, nonNull, false); 321 } 322 323 public static Stamp[] createParameterStamps(ResolvedJavaMethod method) { 324 Signature sig = method.getSignature(); 325 Stamp[] result = new Stamp[sig.getParameterCount(!method.isStatic())]; 326 int index = 0; 327 328 if (!method.isStatic()) { 329 result[index++] = StampFactory.declaredNonNull(method.getDeclaringClass()); 330 } 331 332 int max = sig.getParameterCount(false); 333 ResolvedJavaType accessingClass = method.getDeclaringClass(); 334 for (int i = 0; i < max; i++) { 335 JavaType type = sig.getParameterType(i, accessingClass); 336 Kind kind = type.getKind(); 337 Stamp stamp; 338 if (kind == Kind.Object && type instanceof ResolvedJavaType) { 339 stamp = StampFactory.declared((ResolvedJavaType) type); 340 } else { 341 stamp = StampFactory.forKind(kind); 342 } 343 result[index++] = stamp; 344 } 345 346 return result; 347 } 348 349 public static Stamp pointer() { 350 return rawPointer; 351 } 352}