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