StampFactory.java revision 12651:6ef01bd40ce2
1184588Sdfr/*
2197583Sjamie * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
3197583Sjamie * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4184588Sdfr *
5184588Sdfr * This code is free software; you can redistribute it and/or modify it
6184588Sdfr * under the terms of the GNU General Public License version 2 only, as
7184588Sdfr * published by the Free Software Foundation.
8184588Sdfr *
9184588Sdfr * This code is distributed in the hope that it will be useful, but WITHOUT
10184588Sdfr * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11184588Sdfr * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12184588Sdfr * version 2 for more details (a copy is included in the LICENSE file that
13184588Sdfr * accompanied this code).
14197583Sjamie *
15184588Sdfr * You should have received a copy of the GNU General Public License version
16184588Sdfr * 2 along with this work; if not, write to the Free Software Foundation,
17197583Sjamie * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18184588Sdfr *
19184588Sdfr * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20184588Sdfr * or visit www.oracle.com if you need additional information or have any
21184588Sdfr * questions.
22184588Sdfr */
23184588Sdfrpackage org.graalvm.compiler.core.common.type;
24184588Sdfr
25184588Sdfrimport org.graalvm.compiler.debug.GraalError;
26197583Sjamie
27197583Sjamieimport jdk.vm.ci.code.CodeUtil;
28197583Sjamieimport jdk.vm.ci.meta.Assumptions;
29197583Sjamieimport jdk.vm.ci.meta.JavaConstant;
30197583Sjamieimport jdk.vm.ci.meta.JavaKind;
31184588Sdfrimport jdk.vm.ci.meta.JavaType;
32197583Sjamieimport jdk.vm.ci.meta.MetaAccessProvider;
33197583Sjamieimport jdk.vm.ci.meta.ResolvedJavaMethod;
34197583Sjamieimport jdk.vm.ci.meta.ResolvedJavaType;
35197583Sjamieimport jdk.vm.ci.meta.Signature;
36197583Sjamie
37197583Sjamiepublic class StampFactory {
38197583Sjamie
39197583Sjamie    /*
40197583Sjamie     * The marker stamp for node intrinsics must be its own class, so that it is never equal() to a
41197583Sjamie     * regular ObjectStamp.
42197583Sjamie     */
43197583Sjamie    static final class NodeIntrinsicStamp extends ObjectStamp {
44197583Sjamie        protected static final Stamp SINGLETON = new NodeIntrinsicStamp();
45197583Sjamie
46197583Sjamie        private NodeIntrinsicStamp() {
47197583Sjamie            super(null, false, false, false);
48197583Sjamie        }
49197583Sjamie
50197583Sjamie        @Override
51197583Sjamie        public int hashCode() {
52197583Sjamie            return System.identityHashCode(this);
53197583Sjamie        }
54197583Sjamie
55197583Sjamie        @Override
56197583Sjamie        public boolean equals(Object obj) {
57197583Sjamie            return this == obj;
58197583Sjamie        }
59197583Sjamie    }
60197583Sjamie
61197583Sjamie    // JaCoCo Exclude
62197583Sjamie
63184588Sdfr    private static final Stamp[] stampCache = new Stamp[JavaKind.values().length];
64184588Sdfr    private static final Stamp[] emptyStampCache = new Stamp[JavaKind.values().length];
65184588Sdfr    private static final Stamp objectStamp = new ObjectStamp(null, false, false, false);
66184588Sdfr    private static final Stamp objectNonNullStamp = new ObjectStamp(null, false, true, false);
67197583Sjamie    private static final Stamp objectAlwaysNullStamp = new ObjectStamp(null, false, false, true);
68194239Srmacklem    private static final Stamp positiveInt = forInteger(JavaKind.Int, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE);
69184588Sdfr    private static final Stamp booleanTrue = forInteger(JavaKind.Boolean, -1, -1, 1, 1);
70197583Sjamie    private static final Stamp booleanFalse = forInteger(JavaKind.Boolean, 0, 0, 0, 0);
71184588Sdfr    private static final Stamp rawPointer = new RawPointerStamp();
72184588Sdfr
73184588Sdfr    private static void setCache(JavaKind kind, Stamp stamp) {
74184588Sdfr        stampCache[kind.ordinal()] = stamp;
75197583Sjamie    }
76197583Sjamie
77197583Sjamie    private static void setIntCache(JavaKind kind) {
78184588Sdfr        int bits = kind.getStackKind().getBitCount();
79197583Sjamie        long mask;
80197583Sjamie        if (kind.isUnsigned()) {
81184588Sdfr            mask = CodeUtil.mask(kind.getBitCount());
82197583Sjamie        } else {
83184588Sdfr            mask = CodeUtil.mask(bits);
84197583Sjamie        }
85197583Sjamie        setCache(kind, new IntegerStamp(bits, kind.getMinValue(), kind.getMaxValue(), 0, mask));
86197583Sjamie    }
87197583Sjamie
88197583Sjamie    private static void setFloatCache(JavaKind kind) {
89184588Sdfr        setCache(kind, new FloatStamp(kind.getBitCount()));
90197583Sjamie    }
91197583Sjamie
92197583Sjamie    static {
93197583Sjamie        setIntCache(JavaKind.Boolean);
94184588Sdfr        setIntCache(JavaKind.Byte);
95184588Sdfr        setIntCache(JavaKind.Short);
96197583Sjamie        setIntCache(JavaKind.Char);
97197583Sjamie        setIntCache(JavaKind.Int);
98197583Sjamie        setIntCache(JavaKind.Long);
99197583Sjamie
100197583Sjamie        setFloatCache(JavaKind.Float);
101197583Sjamie        setFloatCache(JavaKind.Double);
102197583Sjamie
103201145Santoine        setCache(JavaKind.Object, objectStamp);
104197583Sjamie        setCache(JavaKind.Void, VoidStamp.getInstance());
105197583Sjamie        setCache(JavaKind.Illegal, IllegalStamp.getInstance());
106197583Sjamie
107197583Sjamie        for (JavaKind k : JavaKind.values()) {
108197583Sjamie            if (stampCache[k.ordinal()] != null) {
109197583Sjamie                emptyStampCache[k.ordinal()] = stampCache[k.ordinal()].empty();
110197583Sjamie            }
111197583Sjamie        }
112197583Sjamie    }
113197583Sjamie
114197583Sjamie    public static Stamp tautology() {
115201145Santoine        return booleanTrue;
116197583Sjamie    }
117197583Sjamie
118197583Sjamie    public static Stamp contradiction() {
119197583Sjamie        return booleanFalse;
120197583Sjamie    }
121197583Sjamie
122197583Sjamie    /**
123197583Sjamie     * Return a stamp for a Java kind, as it would be represented on the bytecode stack.
124201853Sbrooks     */
125201853Sbrooks    public static Stamp forKind(JavaKind kind) {
126201853Sbrooks        assert stampCache[kind.ordinal()] != null : "unexpected forKind(" + kind + ")";
127197583Sjamie        return stampCache[kind.ordinal()];
128197583Sjamie    }
129197583Sjamie
130197583Sjamie    /**
131197583Sjamie     * Return the stamp for the {@code void} type. This will return a singleton instance than can be
132197583Sjamie     * compared using {@code ==}.
133197583Sjamie     */
134197583Sjamie    public static Stamp forVoid() {
135197583Sjamie        return VoidStamp.getInstance();
136197583Sjamie    }
137197583Sjamie
138197583Sjamie    /**
139197583Sjamie     * A stamp used only in the graph of intrinsics, e.g., snippets. It is then replaced by an
140197583Sjamie     * actual stamp when the intrinsic is used, i.e., when the snippet template is instantiated.
141197583Sjamie     */
142197583Sjamie    public static Stamp forNodeIntrinsic() {
143197583Sjamie        return NodeIntrinsicStamp.SINGLETON;
144197583Sjamie    }
145197583Sjamie
146197583Sjamie    public static Stamp intValue() {
147197583Sjamie        return forKind(JavaKind.Int);
148197583Sjamie    }
149197583Sjamie
150197583Sjamie    public static Stamp positiveInt() {
151197583Sjamie        return positiveInt;
152197583Sjamie    }
153201853Sbrooks
154197583Sjamie    public static Stamp empty(JavaKind kind) {
155197583Sjamie        return emptyStampCache[kind.ordinal()];
156197583Sjamie    }
157197583Sjamie
158197583Sjamie    public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound, long downMask, long upMask) {
159197583Sjamie        return new IntegerStamp(kind.getBitCount(), lowerBound, upperBound, downMask, upMask);
160197583Sjamie    }
161197581Sjamie
162197583Sjamie    public static IntegerStamp forInteger(JavaKind kind, long lowerBound, long upperBound) {
163197583Sjamie        return forInteger(kind.getBitCount(), lowerBound, upperBound);
164197583Sjamie    }
165197581Sjamie
166197583Sjamie    /**
167197583Sjamie     * Create a new stamp use {@code newLowerBound} and {@code newUpperBound} computing the
168197583Sjamie     * appropriate {@link IntegerStamp#upMask} and {@link IntegerStamp#downMask} and incorporating
169197583Sjamie     * any mask information from {@code maskStamp}.
170184588Sdfr     *
171184588Sdfr     * @param bits
172197583Sjamie     * @param newLowerBound
173197583Sjamie     * @param newUpperBound
174197583Sjamie     * @param maskStamp
175197583Sjamie     * @return a new stamp with the appropriate bounds and masks
176197583Sjamie     */
177197583Sjamie    public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, IntegerStamp maskStamp) {
178197583Sjamie        IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
179197583Sjamie        return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | maskStamp.downMask(), limit.upMask() & maskStamp.upMask());
180197583Sjamie    }
181184588Sdfr
182197583Sjamie    public static IntegerStamp forIntegerWithMask(int bits, long newLowerBound, long newUpperBound, long newDownMask, long newUpMask) {
183184588Sdfr        IntegerStamp limit = StampFactory.forInteger(bits, newLowerBound, newUpperBound);
184197583Sjamie        return new IntegerStamp(bits, newLowerBound, newUpperBound, limit.downMask() | newDownMask, limit.upMask() & newUpMask);
185197583Sjamie    }
186197583Sjamie
187197583Sjamie    public static IntegerStamp forInteger(int bits) {
188197583Sjamie        return new IntegerStamp(bits, CodeUtil.minValue(bits), CodeUtil.maxValue(bits), 0, CodeUtil.mask(bits));
189197583Sjamie    }
190197583Sjamie
191197583Sjamie    public static IntegerStamp forInteger(int bits, long lowerBound, long upperBound) {
192197583Sjamie        long defaultMask = CodeUtil.mask(bits);
193197583Sjamie        if (lowerBound == upperBound) {
194197583Sjamie            return new IntegerStamp(bits, lowerBound, lowerBound, lowerBound & defaultMask, lowerBound & defaultMask);
195197583Sjamie        }
196197583Sjamie        final long downMask;
197197583Sjamie        final long upMask;
198197583Sjamie        if (lowerBound >= 0) {
199197583Sjamie            int upperBoundLeadingZeros = Long.numberOfLeadingZeros(upperBound);
200197583Sjamie            long differentBits = lowerBound ^ upperBound;
201184588Sdfr            int sameBitCount = Long.numberOfLeadingZeros(differentBits << upperBoundLeadingZeros);
202197583Sjamie
203197583Sjamie            upMask = upperBound | -1L >>> (upperBoundLeadingZeros + sameBitCount);
204197583Sjamie            downMask = upperBound & ~(-1L >>> (upperBoundLeadingZeros + sameBitCount));
205197583Sjamie        } else {
206184588Sdfr            if (upperBound >= 0) {
207197583Sjamie                upMask = defaultMask;
208197583Sjamie                downMask = 0;
209197583Sjamie            } else {
210197583Sjamie                int lowerBoundLeadingOnes = Long.numberOfLeadingZeros(~lowerBound);
211197583Sjamie                long differentBits = lowerBound ^ upperBound;
212197583Sjamie                int sameBitCount = Long.numberOfLeadingZeros(differentBits << lowerBoundLeadingOnes);
213197583Sjamie
214197583Sjamie                upMask = lowerBound | -1L >>> (lowerBoundLeadingOnes + sameBitCount) | ~(-1L >>> lowerBoundLeadingOnes);
215197583Sjamie                downMask = lowerBound & ~(-1L >>> (lowerBoundLeadingOnes + sameBitCount)) | ~(-1L >>> lowerBoundLeadingOnes);
216197583Sjamie            }
217197583Sjamie        }
218197583Sjamie        return new IntegerStamp(bits, lowerBound, upperBound, downMask & defaultMask, upMask & defaultMask);
219197583Sjamie    }
220197583Sjamie
221197583Sjamie    public static FloatStamp forFloat(JavaKind kind, double lowerBound, double upperBound, boolean nonNaN) {
222197583Sjamie        assert kind.isNumericFloat();
223197583Sjamie        return new FloatStamp(kind.getBitCount(), lowerBound, upperBound, nonNaN);
224197583Sjamie    }
225184588Sdfr
226184588Sdfr    public static Stamp forConstant(JavaConstant value) {
227197583Sjamie        JavaKind kind = value.getJavaKind();
228197583Sjamie        switch (kind) {
229184588Sdfr            case Boolean:
230197583Sjamie            case Byte:
231197583Sjamie            case Char:
232197583Sjamie            case Short:
233197583Sjamie            case Int:
234197583Sjamie            case Long:
235197583Sjamie                long mask = value.asLong() & CodeUtil.mask(kind.getBitCount());
236197583Sjamie                return forInteger(kind.getStackKind(), value.asLong(), value.asLong(), mask, mask);
237197583Sjamie            case Float:
238197583Sjamie                return forFloat(kind, value.asFloat(), value.asFloat(), !Float.isNaN(value.asFloat()));
239197583Sjamie            case Double:
240197583Sjamie                return forFloat(kind, value.asDouble(), value.asDouble(), !Double.isNaN(value.asDouble()));
241197583Sjamie            case Illegal:
242197583Sjamie                return forKind(JavaKind.Illegal);
243197583Sjamie            case Object:
244197583Sjamie                if (value.isNull()) {
245197583Sjamie                    return alwaysNull();
246197583Sjamie                } else {
247197583Sjamie                    return objectNonNull();
248197583Sjamie                }
249197583Sjamie            default:
250197583Sjamie                throw new GraalError("unexpected kind: %s", kind);
251197583Sjamie        }
252197583Sjamie    }
253197583Sjamie
254197583Sjamie    public static Stamp forConstant(JavaConstant value, MetaAccessProvider metaAccess) {
255197583Sjamie        if (value.getJavaKind() == JavaKind.Object) {
256197583Sjamie            ResolvedJavaType type = value.isNull() ? null : metaAccess.lookupJavaType(value);
257197583Sjamie            return new ObjectStamp(type, value.isNonNull(), value.isNonNull(), value.isNull());
258184588Sdfr        } else {
259197583Sjamie            return forConstant(value);
260184588Sdfr        }
261197583Sjamie    }
262197583Sjamie
263197583Sjamie    public static Stamp object() {
264197583Sjamie        return objectStamp;
265197583Sjamie    }
266197583Sjamie
267197583Sjamie    public static Stamp objectNonNull() {
268197583Sjamie        return objectNonNullStamp;
269197583Sjamie    }
270197583Sjamie
271197583Sjamie    public static Stamp alwaysNull() {
272197583Sjamie        return objectAlwaysNullStamp;
273197583Sjamie    }
274197583Sjamie
275197583Sjamie    public static ObjectStamp object(TypeReference type) {
276197583Sjamie        return object(type, false);
277197583Sjamie    }
278197583Sjamie
279197583Sjamie    public static ObjectStamp objectNonNull(TypeReference type) {
280197583Sjamie        return object(type, true);
281197583Sjamie    }
282197583Sjamie
283197583Sjamie    public static ObjectStamp object(TypeReference type, boolean nonNull) {
284197583Sjamie        if (type == null) {
285197583Sjamie            return new ObjectStamp(null, false, nonNull, false);
286197583Sjamie        } else {
287197583Sjamie            return new ObjectStamp(type.getType(), type.isExact(), nonNull, false);
288184588Sdfr        }
289197583Sjamie    }
290197583Sjamie
291197583Sjamie    public static Stamp[] createParameterStamps(Assumptions assumptions, ResolvedJavaMethod method) {
292197583Sjamie        Signature sig = method.getSignature();
293197583Sjamie        Stamp[] result = new Stamp[sig.getParameterCount(!method.isStatic())];
294197583Sjamie        int index = 0;
295197583Sjamie
296197583Sjamie        if (!method.isStatic()) {
297197583Sjamie            result[index++] = StampFactory.objectNonNull(TypeReference.create(assumptions, method.getDeclaringClass()));
298197583Sjamie        }
299197583Sjamie
300197583Sjamie        int max = sig.getParameterCount(false);
301197583Sjamie        ResolvedJavaType accessingClass = method.getDeclaringClass();
302197583Sjamie        for (int i = 0; i < max; i++) {
303197583Sjamie            JavaType type = sig.getParameterType(i, accessingClass);
304197583Sjamie            JavaKind kind = type.getJavaKind();
305197583Sjamie            Stamp stamp;
306197583Sjamie            if (kind == JavaKind.Object && type instanceof ResolvedJavaType) {
307197583Sjamie                stamp = StampFactory.object(TypeReference.create(assumptions, (ResolvedJavaType) type));
308197583Sjamie            } else {
309197583Sjamie                stamp = StampFactory.forKind(kind);
310197583Sjamie            }
311197583Sjamie            result[index++] = stamp;
312197583Sjamie        }
313197583Sjamie
314184588Sdfr        return result;
315184588Sdfr    }
316197583Sjamie
317197583Sjamie    public static Stamp pointer() {
318197583Sjamie        return rawPointer;
319197583Sjamie    }
320197583Sjamie
321197583Sjamie    public static StampPair forDeclaredType(Assumptions assumptions, JavaType returnType, boolean nonNull) {
322197583Sjamie        if (returnType.getJavaKind() == JavaKind.Object && returnType instanceof ResolvedJavaType) {
323197583Sjamie            ResolvedJavaType resolvedJavaType = (ResolvedJavaType) returnType;
324197583Sjamie            TypeReference reference = TypeReference.create(assumptions, resolvedJavaType);
325197583Sjamie            if (resolvedJavaType.isInterface()) {
326197583Sjamie                ResolvedJavaType implementor = resolvedJavaType.getSingleImplementor();
327197583Sjamie                if (implementor != null && !resolvedJavaType.equals(implementor)) {
328197583Sjamie                    TypeReference uncheckedType = TypeReference.createTrusted(assumptions, implementor);
329197583Sjamie                    return StampPair.create(StampFactory.object(reference, nonNull), StampFactory.object(uncheckedType, nonNull));
330197583Sjamie                }
331197583Sjamie            }
332197583Sjamie            return StampPair.createSingle(StampFactory.object(reference, nonNull));
333197583Sjamie        } else {
334197583Sjamie            return StampPair.createSingle(StampFactory.forKind(returnType.getJavaKind()));
335197583Sjamie        }
336197583Sjamie    }
337197583Sjamie}
338197583Sjamie