001/*
002 * Copyright (c) 2009, 2014, 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 jdk.internal.jvmci.hotspot;
024
025import static jdk.internal.jvmci.hotspot.HotSpotResolvedObjectTypeImpl.*;
026
027import java.lang.invoke.*;
028
029import jdk.internal.jvmci.meta.*;
030
031/**
032 * Represents a constant non-{@code null} object reference, within the compiler and across the
033 * compiler/runtime interface.
034 */
035public final class HotSpotObjectConstantImpl extends AbstractValue implements HotSpotObjectConstant, HotSpotProxified {
036
037    public static JavaConstant forObject(Object object) {
038        return forObject(object, false);
039    }
040
041    static JavaConstant forObject(Object object, boolean compressed) {
042        if (object == null) {
043            return compressed ? HotSpotCompressedNullConstant.COMPRESSED_NULL : JavaConstant.NULL_POINTER;
044        } else {
045            return new HotSpotObjectConstantImpl(object, compressed);
046        }
047    }
048
049    static JavaConstant forStableArray(Object object, int stableDimension, boolean isDefaultStable) {
050        if (object == null) {
051            return JavaConstant.NULL_POINTER;
052        } else {
053            assert object.getClass().isArray();
054            return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable);
055        }
056    }
057
058    public static JavaConstant forBoxedValue(Kind kind, Object value) {
059        if (kind == Kind.Object) {
060            return HotSpotObjectConstantImpl.forObject(value);
061        } else {
062            return JavaConstant.forBoxedPrimitive(value);
063        }
064    }
065
066    static Object asBoxedValue(Constant constant) {
067        if (JavaConstant.isNull(constant)) {
068            return null;
069        } else if (constant instanceof HotSpotObjectConstantImpl) {
070            return ((HotSpotObjectConstantImpl) constant).object;
071        } else {
072            return ((JavaConstant) constant).asBoxedPrimitive();
073        }
074    }
075
076    private final Object object;
077    private final boolean compressed;
078    private final byte stableDimension;
079    private final boolean isDefaultStable;
080
081    private HotSpotObjectConstantImpl(Object object, boolean compressed, int stableDimension, boolean isDefaultStable) {
082        super(LIRKind.reference(compressed ? Kind.Int : Kind.Object));
083        this.object = object;
084        this.compressed = compressed;
085        this.stableDimension = (byte) stableDimension;
086        this.isDefaultStable = isDefaultStable;
087        assert object != null;
088        assert stableDimension == 0 || (object != null && object.getClass().isArray());
089        assert stableDimension >= 0 && stableDimension <= 255;
090        assert !isDefaultStable || stableDimension > 0;
091    }
092
093    private HotSpotObjectConstantImpl(Object object, boolean compressed) {
094        this(object, compressed, 0, false);
095    }
096
097    /**
098     * Package-private accessor for the object represented by this constant.
099     */
100    Object object() {
101        return object;
102    }
103
104    /**
105     * Determines if the object represented by this constant is {@link Object#equals(Object) equal}
106     * to a given object.
107     */
108    public boolean isEqualTo(Object obj) {
109        return object.equals(obj);
110    }
111
112    /**
113     * Gets the class of the object represented by this constant.
114     */
115    public Class<?> getObjectClass() {
116        return object.getClass();
117    }
118
119    public boolean isCompressed() {
120        return compressed;
121    }
122
123    public JavaConstant compress() {
124        assert !compressed;
125        return new HotSpotObjectConstantImpl(object, true, stableDimension, isDefaultStable);
126    }
127
128    public JavaConstant uncompress() {
129        assert compressed;
130        return new HotSpotObjectConstantImpl(object, false, stableDimension, isDefaultStable);
131    }
132
133    public HotSpotResolvedObjectType getType() {
134        return fromObjectClass(object.getClass());
135    }
136
137    public JavaConstant getClassLoader() {
138        if (object instanceof Class) {
139            /*
140             * This is an intrinsic for getClassLoader0, which occurs after any security checks. We
141             * can't call that directly so just call getClassLoader.
142             */
143            return HotSpotObjectConstantImpl.forObject(((Class<?>) object).getClassLoader());
144        }
145        return null;
146    }
147
148    public int getIdentityHashCode() {
149        return System.identityHashCode(object);
150    }
151
152    public JavaConstant getComponentType() {
153        if (object instanceof Class) {
154            return HotSpotObjectConstantImpl.forObject(((Class<?>) object).getComponentType());
155        }
156        return null;
157    }
158
159    public JavaConstant getSuperclass() {
160        if (object instanceof Class) {
161            return HotSpotObjectConstantImpl.forObject(((Class<?>) object).getSuperclass());
162        }
163        return null;
164    }
165
166    public JavaConstant getCallSiteTarget(Assumptions assumptions) {
167        if (object instanceof CallSite) {
168            CallSite callSite = (CallSite) object;
169            MethodHandle target = callSite.getTarget();
170            if (!(callSite instanceof ConstantCallSite)) {
171                if (assumptions == null) {
172                    return null;
173                }
174                assumptions.record(new Assumptions.CallSiteTargetValue(callSite, target));
175            }
176            return HotSpotObjectConstantImpl.forObject(target);
177        }
178        return null;
179    }
180
181    @SuppressFBWarnings(value = "ES_COMPARING_STRINGS_WITH_EQ", justification = "reference equality is what we want")
182    public boolean isInternedString() {
183        if (object instanceof String) {
184            String s = (String) object;
185            return s.intern() == s;
186        }
187        return false;
188    }
189
190    public <T> T asObject(Class<T> type) {
191        if (type.isInstance(object)) {
192            return type.cast(object);
193        }
194        return null;
195    }
196
197    public Object asObject(ResolvedJavaType type) {
198        if (type.isInstance(this)) {
199            return object;
200        }
201        return null;
202    }
203
204    @Override
205    public boolean isNull() {
206        return false;
207    }
208
209    @Override
210    public boolean isDefaultForKind() {
211        return false;
212    }
213
214    @Override
215    public Object asBoxedPrimitive() {
216        throw new IllegalArgumentException();
217    }
218
219    @Override
220    public int asInt() {
221        throw new IllegalArgumentException();
222    }
223
224    @Override
225    public boolean asBoolean() {
226        throw new IllegalArgumentException();
227    }
228
229    @Override
230    public long asLong() {
231        throw new IllegalArgumentException();
232    }
233
234    @Override
235    public float asFloat() {
236        throw new IllegalArgumentException();
237    }
238
239    @Override
240    public double asDouble() {
241        throw new IllegalArgumentException();
242    }
243
244    @Override
245    public int hashCode() {
246        return System.identityHashCode(object);
247    }
248
249    @Override
250    public boolean equals(Object o) {
251        if (o == this) {
252            return true;
253        } else if (o instanceof HotSpotObjectConstantImpl) {
254            HotSpotObjectConstantImpl other = (HotSpotObjectConstantImpl) o;
255            return super.equals(o) && object == other.object && compressed == other.compressed && stableDimension == other.stableDimension && isDefaultStable == other.isDefaultStable;
256        }
257        return false;
258    }
259
260    @Override
261    public String toValueString() {
262        if (object instanceof String) {
263            return "\"" + (String) object + "\"";
264        } else {
265            return Kind.Object.format(object);
266        }
267    }
268
269    @Override
270    public String toString() {
271        return (compressed ? "NarrowOop" : getKind().getJavaName()) + "[" + Kind.Object.format(object) + "]";
272    }
273
274    /**
275     * Number of stable dimensions if this constant is a stable array.
276     */
277    public int getStableDimension() {
278        return stableDimension & 0xff;
279    }
280
281    /**
282     * Returns {@code true} if this is a stable array constant and its elements should be considered
283     * as stable regardless of whether they are default values.
284     */
285    public boolean isDefaultStable() {
286        return isDefaultStable;
287    }
288}