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.HotSpotConstantReflectionProvider.Options.*;
26
27 import java.lang.reflect.*;
28
29 import jdk.vm.ci.meta.*;
30 import jdk.vm.ci.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 isEmbeddable(Constant constant) {
65 return true;
66 }
67
68 @Override
69 public Boolean constantEquals(Constant x, Constant y) {
70 if (x == y) {
71 return true;
72 } else if (x instanceof HotSpotObjectConstantImpl) {
73 return y instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) x).object() == ((HotSpotObjectConstantImpl) y).object();
74 } else {
75 return x.equals(y);
76 }
77 }
78
79 @Override
80 public Integer readArrayLength(JavaConstant array) {
81 if (array.getJavaKind() != JavaKind.Object || array.isNull()) {
82 return null;
83 }
84
85 Object arrayObject = ((HotSpotObjectConstantImpl) array).object();
86 if (!arrayObject.getClass().isArray()) {
87 return null;
88 }
93 if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) {
94 JavaConstant element = readArrayElement(array, index);
95 if (element != null && (((HotSpotObjectConstantImpl) array).isDefaultStable() || !element.isDefaultForKind())) {
96 return element;
97 }
98 }
99 return null;
100 }
101
102 /**
103 * Try to convert {@code offset} into an an index into {@code array}.
104 *
105 * @return the computed index or -1 if the offset isn't within the array
106 */
107 private int indexForOffset(JavaConstant array, long offset) {
108 if (array.getJavaKind() != JavaKind.Object || array.isNull()) {
109 return -1;
110 }
111 Class<?> componentType = ((HotSpotObjectConstantImpl) array).object().getClass().getComponentType();
112 JavaKind kind = runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType(componentType).getJavaKind();
113 int arraybase = runtime.getArrayBaseOffset(kind);
114 int scale = runtime.getArrayIndexScale(kind);
115 if (offset < arraybase) {
116 return -1;
117 }
118 long index = offset - arraybase;
119 if (index % scale != 0) {
120 return -1;
121 }
122 long result = index / scale;
123 if (result >= Integer.MAX_VALUE) {
124 return -1;
125 }
126 return (int) result;
127 }
128
129 public JavaConstant readConstantArrayElementForOffset(JavaConstant array, long offset) {
130 if (array instanceof HotSpotObjectConstantImpl && ((HotSpotObjectConstantImpl) array).getStableDimension() > 0) {
131 return readConstantArrayElement(array, indexForOffset(array, offset));
132 }
133 return null;
134 }
190 return null;
191 }
192 return HotSpotObjectConstantImpl.forObject(source.asBoxedPrimitive());
193 }
194
195 @Override
196 public JavaConstant unboxPrimitive(JavaConstant source) {
197 if (!source.getJavaKind().isObject()) {
198 return null;
199 }
200 if (source.isNull()) {
201 return null;
202 }
203 return JavaConstant.forBoxedPrimitive(((HotSpotObjectConstantImpl) source).object());
204 }
205
206 public JavaConstant forString(String value) {
207 return HotSpotObjectConstantImpl.forObject(value);
208 }
209
210 @Override
211 public ResolvedJavaType asJavaType(Constant constant) {
212 if (constant instanceof HotSpotObjectConstant) {
213 Object obj = ((HotSpotObjectConstantImpl) constant).object();
214 if (obj instanceof Class) {
215 return runtime.getHostJVMCIBackend().getMetaAccess().lookupJavaType((Class<?>) obj);
216 }
217 }
218 if (constant instanceof HotSpotMetaspaceConstant) {
219 Object obj = HotSpotMetaspaceConstantImpl.getMetaspaceObject(constant);
220 if (obj instanceof HotSpotResolvedObjectTypeImpl) {
221 return (ResolvedJavaType) obj;
222 }
223 }
224 return null;
225 }
226
227 private static final String SystemClassName = "Ljava/lang/System;";
228
229 /**
230 * Determines if a static field is constant for the purpose of
231 * {@link #readConstantFieldValue(JavaField, JavaConstant)}.
232 */
233 protected boolean isStaticFieldConstant(HotSpotResolvedJavaField staticField) {
234 if (staticField.isFinal() || staticField.isStable()) {
235 ResolvedJavaType holder = staticField.getDeclaringClass();
236 if (holder.isInitialized() && !holder.getName().equals(SystemClassName)) {
237 return true;
238 }
239 }
240 return false;
241 }
242
243 /**
244 * Determines if a value read from a {@code final} instance field is considered constant. The
245 * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is
246 * not the {@link JavaConstant#isDefaultForKind default value} for its kind or if
247 * {@link Options#TrustFinalDefaultFields} is true.
248 *
249 * @param value a value read from a {@code final} instance field
250 * @param receiverClass the {@link Object#getClass() class} of object from which the
251 * {@code value} was read
252 */
253 protected boolean isFinalInstanceFieldValueConstant(JavaConstant value, Class<?> receiverClass) {
254 return !value.isDefaultForKind() || TrustFinalDefaultFields.getValue();
255 }
256
257 /**
258 * Determines if a value read from a {@link Stable} instance field is considered constant. The
259 * implementation in {@link HotSpotConstantReflectionProvider} returns true if {@code value} is
260 * not the {@link JavaConstant#isDefaultForKind default value} for its kind.
261 *
262 * @param value a value read from a {@link Stable} field
263 * @param receiverClass the {@link Object#getClass() class} of object from which the
264 * {@code value} was read
265 */
266 protected boolean isStableInstanceFieldValueConstant(JavaConstant value, Class<?> receiverClass) {
267 return !value.isDefaultForKind();
268 }
269
270 /**
271 * {@inheritDoc}
272 * <p>
273 * The {@code value} field in {@link OptionValue} is considered constant if the type of
274 * {@code receiver} is (assignable to) {@link StableOptionValue}.
310 }
311 } else {
312 Class<?> clazz = object.getClass();
313 if (StableOptionValue.class.isAssignableFrom(clazz)) {
314 if (hotspotField.isInObject(object) && hotspotField.getName().equals("value")) {
315 StableOptionValue<?> option = (StableOptionValue<?>) object;
316 return HotSpotObjectConstantImpl.forObject(option.getValue());
317 }
318 }
319 }
320 }
321 }
322 return null;
323 }
324
325 public JavaConstant readFieldValue(JavaField field, JavaConstant receiver) {
326 HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
327 if (!hotspotField.isStable()) {
328 return readNonStableFieldValue(field, receiver);
329 } else {
330 return readStableFieldValue(field, receiver, false);
331 }
332 }
333
334 private JavaConstant readNonStableFieldValue(JavaField field, JavaConstant receiver) {
335 HotSpotResolvedJavaField hotspotField = (HotSpotResolvedJavaField) field;
336 if (hotspotField.isStatic()) {
337 HotSpotResolvedJavaType holder = (HotSpotResolvedJavaType) hotspotField.getDeclaringClass();
338 if (holder.isInitialized()) {
339 return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), HotSpotObjectConstantImpl.forObject(holder.mirror()), hotspotField.offset());
340 }
341 } else {
342 if (receiver.isNonNull() && hotspotField.isInObject(((HotSpotObjectConstantImpl) receiver).object())) {
343 return memoryAccess.readUnsafeConstant(hotspotField.getJavaKind(), receiver, hotspotField.offset());
344 }
345 }
346 return null;
347 }
348
349 public JavaConstant readStableFieldValue(JavaField field, JavaConstant receiver, boolean isDefaultStable) {
350 JavaConstant fieldValue = readNonStableFieldValue(field, receiver);
|
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 }
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 }
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}.
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);
|