comparison jvmci/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java @ 22672:1bbd4a7c274b

Rename jdk.internal.jvmci to jdk.vm.ci
author Tom Rodriguez <tom.rodriguez@oracle.com>
date Thu, 08 Oct 2015 17:28:41 -0700
parents jvmci/jdk.internal.jvmci.hotspot/src/jdk/internal/jvmci/hotspot/HotSpotConstantReflectionProvider.java@47f047ae2b4b
children f4c4cc22a31c
comparison
equal deleted inserted replaced
22671:97f30e4d0e95 22672:1bbd4a7c274b
1 /*
2 * Copyright (c) 2011, 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 jdk.vm.ci.hotspot;
24
25 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayBaseOffset;
26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntimeProvider.getArrayIndexScale;
27
28 import java.lang.reflect.Array;
29
30 import jdk.vm.ci.meta.Constant;
31 import jdk.vm.ci.meta.ConstantReflectionProvider;
32 import jdk.vm.ci.meta.JavaConstant;
33 import jdk.vm.ci.meta.JavaField;
34 import jdk.vm.ci.meta.JavaKind;
35 import jdk.vm.ci.meta.JavaType;
36 import jdk.vm.ci.meta.MemoryAccessProvider;
37 import jdk.vm.ci.meta.MethodHandleAccessProvider;
38 import jdk.vm.ci.meta.ResolvedJavaType;
39 import jdk.vm.ci.options.Option;
40 import jdk.vm.ci.options.OptionType;
41 import jdk.vm.ci.options.OptionValue;
42 import jdk.vm.ci.options.StableOptionValue;
43
44 /**
45 * HotSpot implementation of {@link ConstantReflectionProvider}.
46 */
47 public class HotSpotConstantReflectionProvider implements ConstantReflectionProvider, HotSpotProxified {
48
49 static class Options {
50 //@formatter:off
51 @Option(help = "Constant fold final fields with default values.", type = OptionType.Debug)
52 public static final OptionValue<Boolean> TrustFinalDefaultFields = new OptionValue<>(true);
53 //@formatter:on
54 }
55
56 protected final HotSpotJVMCIRuntimeProvider runtime;
57 protected final HotSpotMethodHandleAccessProvider methodHandleAccess;
58 protected final HotSpotMemoryAccessProviderImpl memoryAccess;
59
60 public HotSpotConstantReflectionProvider(HotSpotJVMCIRuntimeProvider runtime) {
61 this.runtime = runtime;
62 this.methodHandleAccess = new HotSpotMethodHandleAccessProvider(this);
63 this.memoryAccess = new HotSpotMemoryAccessProviderImpl(runtime);
64 }
65
66 public MethodHandleAccessProvider getMethodHandleAccess() {
67 return methodHandleAccess;
68 }
69
70 @Override
71 public MemoryAccessProvider getMemoryAccessProvider() {
72 return memoryAccess;
73 }
74
75 @Override
76 public Boolean constantEquals(Constant x, Constant y) {
77 if (x == y) {
78 return true;
79 } else if (x instanceof HotSpotObjectConstantImpl) {
80 return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object();
81 } else {
82 return x.equals(y);
83 }
84 }
85
86 @Override
87 public Integer readArrayLength(JavaConstant array) {
88 if (array.getJavaKind() != JavaKind.Object || array.isNull()) {
89 return null;
90 }
91
92 Object arrayObject = ((HotSpotObjectConstantImpl) array).object();
93 if (!arrayObject.getClass().isArray()) {
94 return null;
95 }
96 return Array.getLength(arrayObject);
97 }
98
99 public JavaConstant readConstantArrayElement(JavaConstant array, int index) {
100 if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) {
101 JavaConstant element = readArrayElement(array, index);
102 if (element != null && (((HotSpotObjectConstantImpl) array).isDefaultStable() || !element.isDefaultForKind())) {
103 return element;
104 }
105 }
106 return null;
107 }
108
109 /**
110 * Try to convert {@code offset} into an an index into {@code array}.
111 *
112 * @return the computed index or -1 if the offset isn't within the array
113 */
114 private int indexForOffset(JavaConstant array, long offset) {
115 if (array.getJavaKind() != JavaKind.Object || array.isNull()) {
116 return -1;
117 }
118 Class<?> componentType = ((HotSpotObjectConstantImpl) array).object().getClass().getComponentType();
119 JavaKind kind = runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(componentType).getJavaKind();
120 int arraybase = getArrayBaseOffset(kind);
121 int scale = getArrayIndexScale(kind);
122 if (offset < arraybase) {
123 return -1;
124 }
125 long index = offset - arraybase;
126 if (index % scale != 0) {
127 return -1;
128 }
129 long result = index / scale;
130 if (result >= Integer.MAX_VALUE) {
131 return -1;
132 }
133 return (int) result;
134 }
135
136 public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) {
137 if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) {
138 return readConstantArrayElement(array, indexForOffset(array, offset));
139 }
140 return null;
141 }
142
143 @Override
144 public JavaConstant readArrayElement(JavaConstant array, int index) {
145 if (array.getJavaKind() != JavaKind.Object || array.isNull()) {
146 return null;
147 }
148 Object a = ((HotSpotObjectConstantImpl) array).object();
149
150 if (index < 0 || index >= Array.getLength(a)) {
151 return null;
152 }
153
154 if (a instanceof Object[]) {
155 Object element = ((Object[]) a)[index];
156 if (((HotSpotObjectConstantImpl) array).getStableDimension() > 1) {
157 return HotSpotObjectConstantImpl.forStableArray(element, ((HotSpotObjectConstantImpl) array).getStableDimension() - 1, ((HotSpotObjectConstantImpl) array).isDefaultStable());
158 } else {
159 return HotSpotObjectConstantImpl.forObject(element);
160 }
161 } else {
162 return JavaConstant.forBoxedPrimitive(Array.get(a, index));
163 }
164 }
165
166 /**
167 * Check if the constant is a boxed value that is guaranteed to be cached by the platform.
168 * Otherwise the generated code might be the only reference to the boxed value and since object
169 * references from nmethods are weak this can cause GC problems.
170 *
171 * @param source
172 * @return true if the box is cached
173 */
174 private static boolean isBoxCached(JavaConstant source) {
175 switch (source.getJavaKind()) {
176 case Boolean:
177 return true;
178 case Char:
179 return source.asInt() <= 127;
180 case Byte:
181 case Short:
182 case Int:
183 return source.asInt() >= -128 && source.asInt() <= 127;
184 case Long:
185 return source.asLong() >= -128 && source.asLong() <= 127;
186 case Float:
187 case Double:
188 return false;
189 default:
190 throw new IllegalArgumentException("unexpected kind " + source.getJavaKind());
191 }
192 }
193
194 @Override
195 public JavaConstant boxPrimitive(JavaConstant source) {
196 if (!source.getJavaKind().isPrimitive() || !isBoxCached(source)) {
197 return null;
198 }
199 return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive());
200 }
201
202 @Override
203 public JavaConstant unboxPrimitive(JavaConstant source) {
204 if (!source.getJavaKind().isObject()) {
205 return null;
206 }
207 if (source.isNull()) {
208 return null;
209 }
210 return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object());
211 }
212
213 public JavaConstant forString(String value) {
214 return HotSpotObjectConstantImpl.forObject(value);
215 }
216
217 public JavaConstant forObject(Object value) {
218 return HotSpotObjectConstantImpl.forObject(value);
219 }
220
221 @Override
222 public ResolvedJavaType asJavaType(Constant constant) {
223 if (constant instanceof HotSpotObjectConstant) {
224 Object obj = ((HotSpotObjectConstantImpl) constant).object();
225 if (obj instanceof Class) {
226 return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class<?>) obj);
227 }
228 }
229 if (constant instanceof HotSpotMetaspaceConstant) {
230 MetaspaceWrapperObject obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant);
231 if (obj instanceof HotSpotResolvedObjectTypeImpl) {
232 return (ResolvedJavaType) obj;
233 }
234 }
235 return null;
236 }
237
238 private static final String SystemClassName = "Ljava/lang/System;";
239
240 /**
241 * Determines if a static field is constant for the purpose of
242 * {@link #readConstantFieldValue(JavaField, JavaConstant)}.
243 */
244 protected boolean isStaticFieldConstant(HotSpotResolvedJavaField staticField) {
245 if (staticField.isFinal() || staticField.isStable()) {
246 ResolvedJavaType holder = staticField.getDeclaringClass();
247 if (holder.isInitialized() && !holder.getName().equals(SystemClassName)) {
248 return true;
249 }
250 }
251 return false;
252 }
253
254 /**
255 * Determines if a value read from a {@code final} instance field is considered constant. The
256 * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is
257 * not the {@link JavaConstant#isDefaultForKind default value} for its kind or if
258 * {@link Options#TrustFinalDefaultFields} is true.
259 *
260 * @param value a value read from a {@code final} instance field
261 * @param receiverClass the {@link Object#getClass() class} of object from which the
262 * {@code value} was read
263 */
264 protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class<?> receiverClass) {
265 return !value.isDefaultForKind() || Options.TrustFinalDefaultFields.getValue();
266 }
267
268 /**
269 * Determines if a value read from a {@link Stable} instance field is considered constant. The
270 * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is
271 * not the {@link JavaConstant#isDefaultForKind default value} for its kind.
272 *
273 * @param value a value read from a {@link Stable} field
274 * @param receiverClass the {@link Object#getClass() class} of object from which the
275 * {@code value} was read
276 */
277 protected boolean isStableInstanceFieldValueConstant(JavaConstant value, Class<?> receiverClass) {
278 return !value.isDefaultForKind();
279 }
280
281 /**
282 * {@inheritDoc}
283 * <p>
284 * The {@code value} field in {@link OptionValue} is considered constant if the type of
285 * {@code receiver} is (assignable to) {@link StableOptionValue}.
286 */
287 public JavaConstant readConstantFieldValue(JavaField field, JavaConstant receiver) {
288 HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
289
290 if (hotspotField.isStatic()) {
291 if (isStaticFieldConstant(hotspotField)) {
292 JavaConstant value = readFieldValue(field, receiver);
293 if (hotspotField.isFinal() || !value.isDefaultForKind()) {
294 return value;
295 }
296 }
297 } else {
298 /*
299 * for non-static final fields, we must assume that they are only initialized if they
300 * have a non-default value.
301 */
302 Object object = receiver.isNull() ? null : ((HotSpotObjectConstantImpl) receiver).object();
303
304 // Canonicalization may attempt to process an unsafe read before
305 // processing a guard (e.g. a null check or a type check) for this read
306 // so we need to check the object being read
307 if (object != null) {
308 if (hotspotField.isFinal()) {
309 if (hotspotField.isInObject(object)) {
310 JavaConstant value = readFieldValue(field, receiver);
311 if (isFinalInstanceFieldValueConstant(value, object.getClass())) {
312 return value;
313 }
314 }
315 } else if (hotspotField.isStable()) {
316 if (hotspotField.isInObject(object)) {
317 JavaConstant value = readFieldValue(field, receiver);
318 if (isStableInstanceFieldValueConstant(value, object.getClass())) {
319 return value;
320 }
321 }
322 } else {
323 Class<?> clazz = object.getClass();
324 if (StableOptionValue.class.isAssignableFrom(clazz)) {
325 if (hotspotField.isInObject(object) && hotspotField.getName().equals("value")) {
326 StableOptionValue<?> option = (StableOptionValue<?>) object;
327 return HotSpotObjectConstantImpl.forObject(option.getValue());
328 }
329 }
330 }
331 }
332 }
333 return null;
334 }
335
336 public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) {
337 HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
338 if (!hotspotField.isStable()) {
339 return readNonStableFieldValue(field, receiver);
340 } else {
341 return readStableFieldValue(field, receiver, hotspotField.isDefaultStable());
342 }
343 }
344
345 private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) {
346 HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
347 if (hotspotField.isStatic()) {
348 HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
349 if (holder.isInitialized()) {
350 return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset());
351 }
352 } else {
353 if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) {
354 return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), receiver, hotspotField.offset());
355 }
356 }
357 return null;
358 }
359
360 public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) {
361 JavaConstant fieldValue = readNonStableFieldValue(field, receiver);
362 if (fieldValue.isNonNull()) {
363 JavaType declaredType = field.getType();
364 if (declaredType.getComponentType() != null) {
365 int stableDimension = getArrayDimension(declaredType);
366 return HotSpotObjectConstantImpl.forStableArray(((HotSpotObjectConstantImpl) fieldValue).object(), stableDimension, isDefaultStable);
367 }
368 }
369 return fieldValue;
370 }
371
372 private static int getArrayDimension(JavaType type) {
373 int dimensions = 0;
374 JavaType componentType = type;
375 while ((componentType = componentType.getComponentType()) != null) {
376 dimensions++;
377 }
378 return dimensions;
379 }
380 }