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}