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 */
23package jdk.vm.ci.hotspot;
24
25import java.lang.reflect.Array;
26import java.util.Objects;
27
28import jdk.vm.ci.common.JVMCIError;
29import jdk.vm.ci.meta.Constant;
30import jdk.vm.ci.meta.ConstantReflectionProvider;
31import jdk.vm.ci.meta.JavaConstant;
32import jdk.vm.ci.meta.JavaKind;
33import jdk.vm.ci.meta.MemoryAccessProvider;
34import jdk.vm.ci.meta.MethodHandleAccessProvider;
35import jdk.vm.ci.meta.ResolvedJavaField;
36import jdk.vm.ci.meta.ResolvedJavaType;
37
38/**
39 * HotSpot implementation of {@link ConstantReflectionProvider}.
40 */
41public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider {
42
43    protected final HotSpotJVMCIRuntimeProvider runtime;
44    protected final HotSpotMethodHandleAccessProvider methodHandleAccess;
45    protected final HotSpotMemoryAccessProviderImpl memoryAccess;
46
47    public HotSpotConstantReflectionProvider(HotSpotJVMCIRuntimeProvider runtime) {
48        this.runtime = runtime;
49        this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this);
50        this.memoryAccess = new HotSpotMemoryAccessProviderImpl(runtime);
51    }
52
53    public MethodHandleAccessProvider getMethodHandleAccess() {
54        return methodHandleAccess;
55    }
56
57    @Override
58    public MemoryAccessProvider getMemoryAccessProvider() {
59        return memoryAccess;
60    }
61
62    @Override
63    public Boolean constantEquals(Constant x, Constant y) {
64        if (x == y) {
65            return true;
66        } else if (x instanceof HotSpotObjectConstantImpl) {
67            return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object();
68        } else {
69            return Objects.equals(x, y);
70        }
71    }
72
73    @Override
74    public Integer readArrayLength(JavaConstant array) {
75        if (array == null || array.getJavaKind() != JavaKind.Object || array.isNull()) {
76            return null;
77        }
78
79        Object arrayObject = ((HotSpotObjectConstantImpl) array).object();
80        if (!arrayObject.getClass().isArray()) {
81            return null;
82        }
83        return Array.getLength(arrayObject);
84    }
85
86    @Override
87    public JavaConstant readArrayElement(JavaConstant array, int index) {
88        if (array == null || array.getJavaKind() != JavaKind.Object || array.isNull()) {
89            return null;
90        }
91        Object a = ((HotSpotObjectConstantImpl) array).object();
92
93        if (!a.getClass().isArray() || index < 0 || index >= Array.getLength(a)) {
94            return null;
95        }
96
97        if (a instanceof Object[]) {
98            Object element = ((Object[]) a)[index];
99            return HotSpotObjectConstantImpl.forObject(element);
100        } else {
101            return JavaConstant.forBoxedPrimitive(Array.get(a, index));
102        }
103    }
104
105    /**
106     * Check if the constant is a boxed value that is guaranteed to be cached by the platform.
107     * Otherwise the generated code might be the only reference to the boxed value and since object
108     * references from nmethods are weak this can cause GC problems.
109     *
110     * @param source
111     * @return true if the box is cached
112     */
113    private static boolean isBoxCached(JavaConstant source) {
114        switch (source.getJavaKind()) {
115            case Boolean:
116                return true;
117            case Char:
118                return source.asInt() <= 127;
119            case Byte:
120            case Short:
121            case Int:
122                return source.asInt() >= -128 && source.asInt() <= 127;
123            case Long:
124                return source.asLong() >= -128 && source.asLong() <= 127;
125            case Float:
126            case Double:
127                return false;
128            default:
129                throw new IllegalArgumentException("unexpected kind " + source.getJavaKind());
130        }
131    }
132
133    @Override
134    public JavaConstant boxPrimitive(JavaConstant source) {
135        if (source == null || !source.getJavaKind().isPrimitive() || !isBoxCached(source)) {
136            return null;
137        }
138        return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive());
139    }
140
141    @Override
142    public JavaConstant unboxPrimitive(JavaConstant source) {
143        if (source == null || !source.getJavaKind().isObject()) {
144            return null;
145        }
146        if (source.isNull()) {
147            return null;
148        }
149        return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object());
150    }
151
152    public JavaConstant forString(String value) {
153        return HotSpotObjectConstantImpl.forObject(value);
154    }
155
156    public JavaConstant forObject(Object value) {
157        return HotSpotObjectConstantImpl.forObject(value);
158    }
159
160    @Override
161    public ResolvedJavaType asJavaType(Constant constant) {
162        if (constant instanceof HotSpotObjectConstant) {
163            Object obj = ((HotSpotObjectConstantImpl) constant).object();
164            if (obj instanceof Class) {
165                return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class<?>) obj);
166            }
167        }
168        if (constant instanceof HotSpotMetaspaceConstant) {
169            MetaspaceWrapperObject obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant);
170            if (obj instanceof HotSpotResolvedObjectTypeImpl) {
171                return (ResolvedJavaType) obj;
172            }
173        }
174        return null;
175    }
176
177    public JavaConstant readFieldValue(ResolvedJavaField field, JavaConstant receiver) {
178        HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
179        if (hotspotField.isStatic()) {
180            HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
181            if (holder.isInitialized()) {
182                return memoryAccess.readFieldValue(hotspotField, holder.mirror());
183            }
184        } else {
185            if (receiver.isNonNull()) {
186                Object object = ((HotSpotObjectConstantImpl) receiver).object();
187                if (hotspotField.isInObject(object)) {
188                    return memoryAccess.readFieldValue(hotspotField, object);
189                }
190            }
191        }
192        return null;
193    }
194
195    @Override
196    public JavaConstant asJavaClass(ResolvedJavaType type) {
197        return HotSpotObjectConstantImpl.forObject(((HotSpotResolvedJavaType) type).mirror());
198    }
199
200    @Override
201    public Constant asObjectHub(ResolvedJavaType type) {
202        if (type instanceof HotSpotResolvedObjectType) {
203            return ((HotSpotResolvedObjectType) type).klass();
204        } else {
205            throw JVMCIError.unimplemented();
206        }
207    }
208}
209