comparison graal/com.oracle.jvmci.hotspot/src/com/oracle/jvmci/hotspot/HotSpotConstantReflectionProvider.java @ 21551:5324104ac4f3

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