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.meta.*;
026
027import com.oracle.graal.compiler.common.spi.*;
028
029/**
030 * A stamp is the basis for a type system.
031 */
032public abstract class Stamp {
033
034    protected Stamp() {
035    }
036
037    /**
038     * Returns the type of the stamp, guaranteed to be non-null. In some cases, this requires the
039     * lookup of class meta data, therefore the {@link MetaAccessProvider} is mandatory.
040     */
041    public abstract ResolvedJavaType javaType(MetaAccessProvider metaAccess);
042
043    public boolean alwaysDistinct(Stamp other) {
044        return join(other).isEmpty();
045    }
046
047    /**
048     * Gets a Java {@link Kind} that can be used to store a value of this stamp on the Java bytecode
049     * stack. Returns {@link Kind#Illegal} if a value of this stamp can not be stored on the
050     * bytecode stack.
051     */
052    public abstract Kind getStackKind();
053
054    /**
055     * Gets a platform dependent {@link LIRKind} that can be used to store a value of this stamp.
056     */
057    public abstract LIRKind getLIRKind(LIRKindTool tool);
058
059    /**
060     * Returns the union of this stamp and the given stamp. Typically used to create stamps for phi
061     * nodes.
062     *
063     * @param other The stamp that will enlarge this stamp.
064     * @return The union of this stamp and the given stamp.
065     */
066    public abstract Stamp meet(Stamp other);
067
068    /**
069     * Returns the intersection of this stamp and the given stamp.
070     *
071     * @param other The stamp that will tighten this stamp.
072     * @return The intersection of this stamp and the given stamp.
073     */
074    public abstract Stamp join(Stamp other);
075
076    /**
077     * Returns a stamp of the same kind, but allowing the full value range of the kind.
078     *
079     * {@link #unrestricted()} is the neutral element of the {@link #join(Stamp)} operation.
080     */
081    public abstract Stamp unrestricted();
082
083    /**
084     * Returns a stamp of the same kind, but with no allowed values.
085     *
086     * {@link #empty()} is the neutral element of the {@link #meet(Stamp)} operation.
087     */
088    public abstract Stamp empty();
089
090    /**
091     * If it is possible to represent single value stamps of this kind, this method returns the
092     * stamp representing the single value c. stamp.constant(c).asConstant() should be equal to c.
093     * <p>
094     * If it is not possible to represent single value stamps, this method returns a stamp that
095     * includes c, and is otherwise as narrow as possible.
096     */
097    public abstract Stamp constant(Constant c, MetaAccessProvider meta);
098
099    /**
100     * Test whether two stamps have the same base type.
101     */
102    public abstract boolean isCompatible(Stamp other);
103
104    /**
105     * Test whether this stamp has legal values.
106     */
107    public abstract boolean hasValues();
108
109    /**
110     * Tests whether this stamp represents an illegal value.
111     */
112    public final boolean isEmpty() {
113        return !hasValues();
114    }
115
116    /**
117     * If this stamp represents a single value, the methods returns this single value. It returns
118     * null otherwise.
119     *
120     * @return the constant corresponding to the single value of this stamp and null if this stamp
121     *         can represent less or more than one value.
122     */
123    public Constant asConstant() {
124        return null;
125    }
126
127    /**
128     * Read a value of this stamp from memory.
129     */
130    public abstract Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement);
131
132    /**
133     * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
134     * improved stamp. Otherwise, returns a stamp equal to this.
135     *
136     * @param other the stamp that should be used to improve this stamp
137     * @return the newly improved stamp or a stamp equal to {@code this} if an improvement was not
138     *         possible
139     */
140    public abstract Stamp improveWith(Stamp other);
141
142    /**
143     * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
144     * improved stamp. Otherwise, returns null.
145     *
146     * @param other the stamp that should be used to improve this stamp
147     * @return the newly improved stamp or {@code null} if an improvement was not possible
148     */
149    public final Stamp tryImproveWith(Stamp other) {
150        Stamp improved = improveWith(other);
151        if (improved.equals(this)) {
152            return null;
153        }
154        return improved;
155    }
156
157    public boolean neverDistinct(Stamp other) {
158        Constant constant = this.asConstant();
159        if (constant != null) {
160            Constant otherConstant = other.asConstant();
161            return otherConstant != null && constant.equals(otherConstant);
162        }
163        return false;
164    }
165}