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