001/*
002 * Copyright (c) 2014, 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.hotspot.nodes.type;
024
025import java.util.*;
026
027import jdk.internal.jvmci.hotspot.*;
028import jdk.internal.jvmci.hotspot.HotSpotVMConfig.*;
029import jdk.internal.jvmci.meta.*;
030
031import com.oracle.graal.compiler.common.spi.*;
032import com.oracle.graal.compiler.common.type.*;
033
034public final class KlassPointerStamp extends MetaspacePointerStamp {
035
036    private final CompressEncoding encoding;
037
038    private final Kind kind;
039
040    public KlassPointerStamp(boolean nonNull, boolean alwaysNull, Kind kind) {
041        this(nonNull, alwaysNull, null, kind);
042    }
043
044    private KlassPointerStamp(boolean nonNull, boolean alwaysNull, CompressEncoding encoding, Kind kind) {
045        super(nonNull, alwaysNull);
046        this.encoding = encoding;
047        this.kind = kind;
048    }
049
050    @Override
051    protected AbstractPointerStamp copyWith(boolean newNonNull, boolean newAlwaysNull) {
052        return new KlassPointerStamp(newNonNull, newAlwaysNull, encoding, kind);
053    }
054
055    @Override
056    public boolean isCompatible(Stamp otherStamp) {
057        if (this == otherStamp) {
058            return true;
059        }
060        if (otherStamp instanceof KlassPointerStamp) {
061            KlassPointerStamp other = (KlassPointerStamp) otherStamp;
062            return Objects.equals(this.encoding, other.encoding);
063        }
064        return false;
065    }
066
067    @Override
068    public Stamp constant(Constant c, MetaAccessProvider meta) {
069        if (isCompressed()) {
070            if (HotSpotCompressedNullConstant.COMPRESSED_NULL.equals(c)) {
071                return new KlassPointerStamp(false, true, encoding, kind);
072            }
073        } else {
074            if (JavaConstant.NULL_POINTER.equals(c)) {
075                return new KlassPointerStamp(false, true, encoding, kind);
076            }
077        }
078
079        assert c instanceof HotSpotMetaspaceConstant;
080        assert ((HotSpotMetaspaceConstant) c).isCompressed() == isCompressed();
081        if (nonNull()) {
082            return this;
083        }
084        return new KlassPointerStamp(true, false, encoding, kind);
085    }
086
087    @Override
088    public Constant asConstant() {
089        if (alwaysNull() && isCompressed()) {
090            return HotSpotCompressedNullConstant.COMPRESSED_NULL;
091        } else {
092            return super.asConstant();
093        }
094    }
095
096    @Override
097    public LIRKind getLIRKind(LIRKindTool tool) {
098        if (isCompressed()) {
099            return LIRKind.value(Kind.Int);
100        } else {
101            return super.getLIRKind(tool);
102        }
103    }
104
105    public boolean isCompressed() {
106        return encoding != null;
107    }
108
109    public CompressEncoding getEncoding() {
110        return encoding;
111    }
112
113    public KlassPointerStamp compressed(CompressEncoding newEncoding) {
114        assert !isCompressed();
115        return new KlassPointerStamp(nonNull(), alwaysNull(), newEncoding, Kind.Int);
116    }
117
118    public KlassPointerStamp uncompressed() {
119        assert isCompressed();
120        return new KlassPointerStamp(nonNull(), alwaysNull(), Kind.Long);
121    }
122
123    @Override
124    public Constant readConstant(MemoryAccessProvider provider, Constant base, long displacement) {
125        HotSpotMemoryAccessProvider hsProvider = (HotSpotMemoryAccessProvider) provider;
126        if (isCompressed()) {
127            return hsProvider.readNarrowKlassPointerConstant(base, displacement, encoding);
128        } else {
129            return hsProvider.readKlassPointerConstant(base, displacement);
130        }
131    }
132
133    @Override
134    public int hashCode() {
135        final int prime = 31;
136        int result = super.hashCode();
137        result = prime * result + ((encoding == null) ? 0 : encoding.hashCode());
138        return result;
139    }
140
141    @Override
142    public boolean equals(Object obj) {
143        if (this == obj) {
144            return true;
145        }
146        if (!super.equals(obj)) {
147            return false;
148        }
149        if (!(obj instanceof KlassPointerStamp)) {
150            return false;
151        }
152        KlassPointerStamp other = (KlassPointerStamp) obj;
153        return Objects.equals(this.encoding, other.encoding);
154    }
155
156    @Override
157    public String toString() {
158        StringBuilder ret = new StringBuilder("Klass*");
159        appendString(ret);
160        if (isCompressed()) {
161            ret.append("(compressed ").append(encoding).append(")");
162        }
163        return ret.toString();
164    }
165
166    @Override
167    public Kind getStackKind() {
168        return isCompressed() ? Kind.Int : Kind.Long;
169    }
170}