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