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 org.graalvm.compiler.core.common.LIRKind;
26import org.graalvm.compiler.core.common.spi.LIRKindTool;
27
28import jdk.vm.ci.meta.Constant;
29import jdk.vm.ci.meta.JavaKind;
30import jdk.vm.ci.meta.MemoryAccessProvider;
31import jdk.vm.ci.meta.MetaAccessProvider;
32import jdk.vm.ci.meta.ResolvedJavaType;
33
34/**
35 * A stamp is the basis for a type system.
36 */
37public abstract class Stamp {
38
39    protected Stamp() {
40    }
41
42    /**
43     * Returns the type of the stamp, guaranteed to be non-null. In some cases, this requires the
44     * lookup of class meta data, therefore the {@link MetaAccessProvider} is mandatory.
45     */
46    public abstract ResolvedJavaType javaType(MetaAccessProvider metaAccess);
47
48    public boolean alwaysDistinct(Stamp other) {
49        return join(other).isEmpty();
50    }
51
52    /**
53     * Gets a Java {@link JavaKind} that can be used to store a value of this stamp on the Java
54     * bytecode stack. Returns {@link JavaKind#Illegal} if a value of this stamp can not be stored
55     * on the bytecode stack.
56     */
57    public abstract JavaKind getStackKind();
58
59    /**
60     * Gets a platform dependent {@link LIRKind} that can be used to store a value of this stamp.
61     */
62    public abstract LIRKind getLIRKind(LIRKindTool tool);
63
64    /**
65     * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi
66     * nodes.
67     *
68     * @param other The stamp that will enlarge this stamp.
69     * @return The union of this stamp and the given stamp.
70     */
71    public abstract Stamp meet(Stamp other);
72
73    /**
74     * Returns the intersection of this stamp and the given stamp.
75     *
76     * @param other The stamp that will tighten this stamp.
77     * @return The intersection of this stamp and the given stamp.
78     */
79    public abstract Stamp join(Stamp other);
80
81    /**
82     * Returns a stamp of the same kind, but allowing the full value range of the kind.
83     *
84     * {@link #unrestricted()} is the neutral element of the {@link #join(Stamp)} operation.
85     */
86    public abstract Stamp unrestricted();
87
88    /**
89     * Returns a stamp of the same kind, but with no allowed values.
90     *
91     * {@link #empty()} is the neutral element of the {@link #meet(Stamp)} operation.
92     */
93    public abstract Stamp empty();
94
95    /**
96     * If it is possible to represent single value stamps of this kind, this method returns the
97     * stamp representing the single value c. stamp.constant(c).asConstant() should be equal to c.
98     * <p>
99     * If it is not possible to represent single value stamps, this method returns a stamp that
100     * includes c, and is otherwise as narrow as possible.
101     */
102    public abstract Stamp constant(Constant c, MetaAccessProvider meta);
103
104    /**
105     * Test whether two stamps have the same base type.
106     */
107    public abstract boolean isCompatible(Stamp other);
108
109    /**
110     * Check that the constant {@code other} is compatible with this stamp.
111     *
112     * @param constant
113     */
114    public abstract boolean isCompatible(Constant constant);
115
116    /**
117     * Test whether this stamp has legal values.
118     */
119    public abstract boolean hasValues();
120
121    /**
122     * Tests whether this stamp represents an illegal value.
123     */
124    public final boolean isEmpty() {
125        return !hasValues();
126    }
127
128    /**
129     * Tests whether this stamp represents all values of this kind.
130     */
131    public boolean isUnrestricted() {
132        return this.equals(this.unrestricted());
133    }
134
135    /**
136     * If this stamp represents a single value, the methods returns this single value. It returns
137     * null otherwise.
138     *
139     * @return the constant corresponding to the single value of this stamp and null if this stamp
140     *         can represent less or more than one value.
141     */
142    public Constant asConstant() {
143        return null;
144    }
145
146    /**
147     * Read a value of this stamp from memory.
148     *
149     * @return the value read or null if the value can't be read for some reason.
150     */
151    public abstract Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement);
152
153    /**
154     * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
155     * improved stamp. Otherwise, returns a stamp equal to this.
156     *
157     * @param other the stamp that should be used to improve this stamp
158     * @return the newly improved stamp or a stamp equal to {@code this} if an improvement was not
159     *         possible
160     */
161    public abstract Stamp improveWith(Stamp other);
162
163    /**
164     * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
165     * improved stamp. Otherwise, returns null.
166     *
167     * @param other the stamp that should be used to improve this stamp
168     * @return the newly improved stamp or {@code null} if an improvement was not possible
169     */
170    public final Stamp tryImproveWith(Stamp other) {
171        Stamp improved = improveWith(other);
172        if (improved.equals(this)) {
173            return null;
174        }
175        return improved;
176    }
177
178    public boolean neverDistinct(Stamp other) {
179        Constant constant = this.asConstant();
180        if (constant != null) {
181            Constant otherConstant = other.asConstant();
182            return otherConstant != null && constant.equals(otherConstant);
183        }
184        return false;
185    }
186}
187