1 /*
   2  * Copyright (c) 2014, 2015, 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.hotspot.nodes.type;
  24 
  25 import java.util.Objects;
  26 
  27 import org.graalvm.compiler.core.common.LIRKind;
  28 import org.graalvm.compiler.core.common.spi.LIRKindTool;
  29 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
  30 import org.graalvm.compiler.core.common.type.Stamp;
  31 import org.graalvm.compiler.hotspot.CompressEncoding;
  32 
  33 import jdk.vm.ci.hotspot.HotSpotCompressedNullConstant;
  34 import jdk.vm.ci.hotspot.HotSpotMemoryAccessProvider;
  35 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
  36 import jdk.vm.ci.meta.Constant;
  37 import jdk.vm.ci.meta.JavaConstant;
  38 import jdk.vm.ci.meta.MemoryAccessProvider;
  39 import jdk.vm.ci.meta.MetaAccessProvider;
  40 
  41 public final class KlassPointerStamp extends MetaspacePointerStamp {
  42 
  43     private static final KlassPointerStamp KLASS = new KlassPointerStamp(false, false);
  44 
  45     private static final KlassPointerStamp KLASS_NON_NULL = new KlassPointerStamp(true, false);
  46 
  47     private static final KlassPointerStamp KLASS_ALWAYS_NULL = new KlassPointerStamp(false, true);
  48 
  49     private final CompressEncoding encoding;
  50 
  51     public static KlassPointerStamp klass() {
  52         return KLASS;
  53     }
  54 
  55     public static KlassPointerStamp klassNonNull() {
  56         return KLASS_NON_NULL;
  57     }
  58 
  59     public static KlassPointerStamp klassAlwaysNull() {
  60         return KLASS_ALWAYS_NULL;
  61     }
  62 
  63     private KlassPointerStamp(boolean nonNull, boolean alwaysNull) {
  64         this(nonNull, alwaysNull, null);
  65     }
  66 
  67     private KlassPointerStamp(boolean nonNull, boolean alwaysNull, CompressEncoding encoding) {
  68         super(nonNull, alwaysNull);
  69         this.encoding = encoding;
  70     }
  71 
  72     @Override
  73     protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
  74         return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding);
  75     }
  76 
  77     @Override
  78     public boolean isCompatible(Stamp otherStamp) {
  79         if (this == otherStamp) {
  80             return true;
  81         }
  82         if (otherStamp instanceof KlassPointerStamp) {
  83             KlassPointerStamp other = (KlassPointerStamp) otherStamp;
  84             return Objects.equals(this.encoding, other.encoding);
  85         }
  86         return false;
  87     }
  88 
  89     @Override
  90     public boolean isCompatible(Constant constant) {
  91         if (constant instanceof HotSpotMetaspaceConstant) {
  92             return ((HotSpotMetaspaceConstant) constant).asResolvedJavaType() != null;
  93         } else {
  94             return super.isCompatible(constant);
  95         }
  96     }
  97 
  98     @Override
  99     public Stamp constant(Constant c, MetaAccessProvider meta) {
 100         if (isCompressed()) {
 101             if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
 102                 return new KlassPointerStamp(false, true, encoding);
 103             }
 104         } else {
 105             if (JavaConstant.NULL_POINTER.equals(c)) {
 106                 return KLASS_ALWAYS_NULL;
 107             }
 108         }
 109 
 110         assert c instanceof HotSpotMetaspaceConstant;
 111         assert ((HotSpotMetaspaceConstant) c).isCompressed() == isCompressed();
 112         if (nonNull()) {
 113             return this;
 114         }
 115         if (isCompressed()) {
 116             return new KlassPointerStamp(true, false, encoding);
 117         } else {
 118             return KLASS_NON_NULL;
 119         }
 120     }
 121 
 122     @Override
 123     public Constant asConstant() {
 124         if (alwaysNull() && isCompressed()) {
 125             return HotSpotCompressedNullConstant.COMPRESSED_NULL;
 126         } else {
 127             return super.asConstant();
 128         }
 129     }
 130 
 131     @Override
 132     public LIRKind getLIRKind(LIRKindTool tool) {
 133         if (isCompressed()) {
 134             return ((HotSpotLIRKindTool) tool).getNarrowPointerKind();
 135         } else {
 136             return super.getLIRKind(tool);
 137         }
 138     }
 139 
 140     public boolean isCompressed() {
 141         return encoding != null;
 142     }
 143 
 144     public CompressEncoding getEncoding() {
 145         return encoding;
 146     }
 147 
 148     public KlassPointerStamp compressed(CompressEncoding newEncoding) {
 149         assert !isCompressed();
 150         return new KlassPointerStamp(nonNull(), alwaysNull(), newEncoding);
 151     }
 152 
 153     public KlassPointerStamp uncompressed() {
 154         assert isCompressed();
 155         return new KlassPointerStamp(nonNull(), alwaysNull());
 156     }
 157 
 158     @Override
 159     public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
 160         HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider;
 161         if (isCompressed()) {
 162             return hsProvider.readNarrowKlassPointerConstant(base, displacement);
 163         } else {
 164             return hsProvider.readKlassPointerConstant(base, displacement);
 165         }
 166     }
 167 
 168     @Override
 169     public int hashCode() {
 170         final int prime = 31;
 171         int result = super.hashCode();
 172         result = prime * result + ((encoding == null) ? 0 : encoding.hashCode());
 173         return result;
 174     }
 175 
 176     @Override
 177     public boolean equals(Object obj) {
 178         if (this == obj) {
 179             return true;
 180         }
 181         if (!super.equals(obj)) {
 182             return false;
 183         }
 184         if (!(obj instanceof KlassPointerStamp)) {
 185             return false;
 186         }
 187         KlassPointerStamp other = (KlassPointerStamp) obj;
 188         return Objects.equals(this.encoding, other.encoding);
 189     }
 190 
 191     @Override
 192     public String toString() {
 193         StringBuilder ret = new StringBuilder("Klass*");
 194         appendString(ret);
 195         if (isCompressed()) {
 196             ret.append("(compressed ").append(encoding).append(")");
 197         }
 198         return ret.toString();
 199     }
 200 }