StampFactory.java revision 12968:4d8a004e5c6d
11900Swollman/*
250477Speter * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
31900Swollman * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41900Swollman *
5156528Sdeischen * This code is free software; you can redistribute it and/or modify it
674848Sru * under the terms of the GNU General Public License version 2 only, as
71900Swollman * published by the Free Software Foundation.
8156528Sdeischen *
91900Swollman * This code is distributed in the hope that it will be useful, but WITHOUT
101900Swollman * 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    /*
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}
335