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 */
23package org.graalvm.compiler.core.common.type;
24
25import static jdk.vm.ci.code.CodeUtil.signExtend;
26
27import org.graalvm.compiler.core.common.NumUtil;
28import org.graalvm.compiler.debug.GraalError;
29
30import jdk.vm.ci.code.CodeUtil;
31import jdk.vm.ci.meta.Assumptions;
32import jdk.vm.ci.meta.JavaConstant;
33import jdk.vm.ci.meta.JavaKind;
34import jdk.vm.ci.meta.JavaType;
35import jdk.vm.ci.meta.MetaAccessProvider;
36import jdk.vm.ci.meta.ResolvedJavaMethod;
37import jdk.vm.ci.meta.ResolvedJavaType;
38import jdk.vm.ci.meta.Signature;
39
40public class StampFactory {
41
42    // JaCoCo Exclude
43
44    private static final Stamp[] stampCache = new Stamp[JavaKind.values().length];
45    private static final Stamp[] emptyStampCache = new Stamp[JavaKind.values().length];
46    private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
47    private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
48    private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
49    private static final Stamp positiveInt = forInteger(JavaKind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
50    private static final Stamp booleanTrue = forInteger(JavaKind.Boolean, -1, -1, 1, 1);
51    private static final Stamp booleanFalse = forInteger(JavaKind.Boolean, 0, 0, 0, 0);
52    private static final Stamp rawPointer = new RawPointerStamp();
53
54    private static void setCache(JavaKind kind, Stamp stamp) {
55        stampCache[kind.ordinal()] = stamp;
56    }
57
58    private static void setIntCache(JavaKind kind) {
59        int bits = kind.getStackKind().getBitCount();
60        long mask;
61        if (kind.isUnsigned()) {
62            mask = CodeUtil.mask(kind.getBitCount());
63        } else {
64            mask = CodeUtil.mask(bits);
65        }
66        setCache(kind, IntegerStamp.create(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
67    }
68
69    private static void setFloatCache(JavaKind kind) {
70        setCache(kind, new FloatStamp(kind.getBitCount()));
71    }
72
73    static {
74        setIntCache(JavaKind.Boolean);
75        setIntCache(JavaKind.Byte);
76        setIntCache(JavaKind.Short);
77        setIntCache(JavaKind.Char);
78        setIntCache(JavaKind.Int);
79        setIntCache(JavaKind.Long);
80
81        setFloatCache(JavaKind.Float);
82        setFloatCache(JavaKind.Double);
83
84        setCache(JavaKind.Object, objectStamp);
85        setCache(JavaKind.Void, VoidStamp.getInstance());
86        setCache(JavaKind.Illegal, IllegalStamp.getInstance());
87
88        for (JavaKind k : JavaKind.values()) {
89            if (stampCache[k.ordinal()] != null) {
90                emptyStampCache[k.ordinal()] = stampCache[k.ordinal()].empty();
91            }
92        }
93    }
94
95    public static Stamp tautology() {
96        return booleanTrue;
97    }
98
99    public static Stamp contradiction() {
100        return booleanFalse;
101    }
102
103    /**
104     * Return a stamp for a Java kind, as it would be represented on the bytecode stack.
105     */
106    public static Stamp forKind(JavaKind kind) {
107        assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")";
108        return stampCache[kind.ordinal()];
109    }
110
111    /**
112     * Return the stamp for the {@code void} type. This will return a singleton instance than can be
113     * compared using {@code ==}.
114     */
115    public static Stamp forVoid() {
116        return VoidStamp.getInstance();
117    }
118
119    public static Stamp intValue() {
120        return forKind(JavaKind.Int);
121    }
122
123    public static Stamp positiveInt() {
124        return positiveInt;
125    }
126
127    public static Stamp empty(JavaKind kind) {
128        return emptyStampCache[kind.ordinal()];
129    }
130
131    public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) {
132        return IntegerStamp.create(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
133    }
134
135    public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) {
136        return forInteger(kind.getBitCount(), lowerBound, upperBound);
137    }
138
139    /**
140     * Create a new stamp use {@code newLowerBound} and {@code newUpperBound} computing the
141     * appropriate {@link IntegerStamp#upMask} and {@link IntegerStamp#downMask} and incorporating
142     * any mask information from {@code maskStamp}.
143     *
144     * @param bits
145     * @param newLowerBound
146     * @param newUpperBound
147     * @param maskStamp
148     * @return a new stamp with the appropriate bounds and masks
149     */
150    public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) {
151        IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
152        return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
153    }
154
155    public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) {
156        IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
157        return IntegerStamp.create(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
158    }
159
160    public static IntegerStamp forInteger(int bits) {
161        return IntegerStamp.create(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
162    }
163
164    public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound) {
165        return forUnsignedInteger(bits, unsignedLowerBound, unsignedUpperBound, 0, CodeUtil.mask(bits));
166    }
167
168    public static IntegerStamp forUnsignedInteger(int bits, long unsignedLowerBound, long unsignedUpperBound, long downMask, long upMask) {
169        long lowerBound = signExtend(unsignedLowerBound, bits);
170        long upperBound = signExtend(unsignedUpperBound, bits);
171        if (!NumUtil.sameSign(lowerBound, upperBound)) {
172            lowerBound = CodeUtil.minValue(bits);
173            upperBound = CodeUtil.maxValue(bits);
174        }
175        long mask = CodeUtil.mask(bits);
176        return IntegerStamp.create(bits, lowerBound, upperBound, downMask & mask, upMask & mask);
177    }
178
179    public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
180        return IntegerStamp.create(bits, lowerBound, upperBound, 0, CodeUtil.mask(bits));
181    }
182
183    public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) {
184        assert kind.isNumericFloat();
185        return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN);
186    }
187
188    public static Stamp forConstant(JavaConstant value) {
189        JavaKind kind = value.getJavaKind();
190        switch (kind) {
191            case Boolean:
192            case Byte:
193            case Char:
194            case Short:
195            case Int:
196            case Long:
197                long mask = value.asLong() & CodeUtil.mask(kind.getBitCount());
198                return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask);
199            case Float:
200                return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
201            case Double:
202                return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
203            case Illegal:
204                return forKind(JavaKind.Illegal);
205            case Object:
206                if (value.isNull()) {
207                    return alwaysNull();
208                } else {
209                    return objectNonNull();
210                }
211            default:
212                throw new GraalError("unexpected kind: %s", kind);
213        }
214    }
215
216    public static Stamp forConstant(JavaConstant value, MetaAccessProvider metaAccess) {
217        if (value.getJavaKind() == JavaKind.Object) {
218            ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value);
219            return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
220        } else {
221            return forConstant(value);
222        }
223    }
224
225    public static Stamp object() {
226        return objectStamp;
227    }
228
229    public static Stamp objectNonNull() {
230        return objectNonNullStamp;
231    }
232
233    public static Stamp alwaysNull() {
234        return objectAlwaysNullStamp;
235    }
236
237    public static ObjectStamp object(TypeReference type) {
238        return object(type, false);
239    }
240
241    public static ObjectStamp objectNonNull(TypeReference type) {
242        return object(type, true);
243    }
244
245    public static ObjectStamp object(TypeReference type, boolean nonNull) {
246        if (type == null) {
247            return new ObjectStamp(null, false, nonNull, false);
248        } else {
249            return new ObjectStamp(type.getType(), type.isExact(), nonNull, false);
250        }
251    }
252
253    public static Stamp[] createParameterStamps(Assumptions assumptions, ResolvedJavaMethod method) {
254        Signature sig = method.getSignature();
255        Stamp[] result = new Stamp[sig.getParameterCount(!method.isStatic())];
256        int index = 0;
257
258        if (!method.isStatic()) {
259            result[index++] = StampFactory.objectNonNull(TypeReference.create(assumptions, method.getDeclaringClass()));
260        }
261
262        int max = sig.getParameterCount(false);
263        ResolvedJavaType accessingClass = method.getDeclaringClass();
264        for (int i = 0; i < max; i++) {
265            JavaType type = sig.getParameterType(i, accessingClass);
266            JavaKind kind = type.getJavaKind();
267            Stamp stamp;
268            if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
269                stamp = StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) type));
270            } else {
271                stamp = StampFactory.forKind(kind);
272            }
273            result[index++] = stamp;
274        }
275
276        return result;
277    }
278
279    public static Stamp pointer() {
280        return rawPointer;
281    }
282
283    public static StampPair forDeclaredType(Assumptions assumptions, JavaType returnType, boolean nonNull) {
284        if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) {
285            ResolvedJavaType resolvedJavaType = (ResolvedJavaType) returnType;
286            TypeReference reference = TypeReference.create(assumptions, resolvedJavaType);
287            if (resolvedJavaType.isInterface()) {
288                ResolvedJavaType implementor = resolvedJavaType.getSingleImplementor();
289                if (implementor != null && !resolvedJavaType.equals(implementor)) {
290                    TypeReference uncheckedType = TypeReference.createTrusted(assumptions, implementor);
291                    return StampPair.create(StampFactory.object(reference, nonNull), StampFactory.object(uncheckedType, nonNull));
292                }
293            }
294            return StampPair.createSingle(StampFactory.object(reference, nonNull));
295        } else {
296            return StampPair.createSingle(StampFactory.forKind(returnType.getJavaKind()));
297        }
298    }
299}
300