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  */
  23 package org.graalvm.compiler.core.common.type;
  24 
  25 import org.graalvm.compiler.core.common.LIRKind;
  26 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  27 
  28 import jdk.vm.ci.meta.Constant;
  29 import jdk.vm.ci.meta.JavaKind;
  30 import jdk.vm.ci.meta.MemoryAccessProvider;
  31 import jdk.vm.ci.meta.MetaAccessProvider;
  32 import jdk.vm.ci.meta.ResolvedJavaType;
  33 
  34 /**
  35  * A stamp is the basis for a type system.
  36  */
  37 public 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      * If this stamp represents a single value, the methods returns this single value. It returns
 130      * null otherwise.
 131      *
 132      * @return the constant corresponding to the single value of this stamp and null if this stamp
 133      *         can represent less or more than one value.
 134      */
 135     public Constant asConstant() {
 136         return null;
 137     }
 138 
 139     /**
 140      * Read a value of this stamp from memory.
 141      */
 142     public abstract Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement);
 143 
 144     /**
 145      * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
 146      * improved stamp. Otherwise, returns a stamp equal to this.
 147      *
 148      * @param other the stamp that should be used to improve this stamp
 149      * @return the newly improved stamp or a stamp equal to {@code this} if an improvement was not
 150      *         possible
 151      */
 152     public abstract Stamp improveWith(Stamp other);
 153 
 154     /**
 155      * Tries to improve this stamp with the stamp given as parameter. If successful, returns the new
 156      * improved stamp. Otherwise, returns null.
 157      *
 158      * @param other the stamp that should be used to improve this stamp
 159      * @return the newly improved stamp or {@code null} if an improvement was not possible
 160      */
 161     public final Stamp tryImproveWith(Stamp other) {
 162         Stamp improved = improveWith(other);
 163         if (improved.equals(this)) {
 164             return null;
 165         }
 166         return improved;
 167     }
 168 
 169     public boolean neverDistinct(Stamp other) {
 170         Constant constant = this.asConstant();
 171         if (constant != null) {
 172             Constant otherConstant = other.asConstant();
 173             return otherConstant != null && constant.equals(otherConstant);
 174         }
 175         return false;
 176     }
 177 }