1 /* 2 * Copyright (c) 2018, 2019, 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.CompilerToVM.compilerToVM; 26 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; 27 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 28 29 import java.lang.annotation.Annotation; 30 import java.lang.reflect.Array; 31 import java.lang.reflect.Executable; 32 import java.lang.reflect.Field; 33 import java.lang.reflect.Method; 34 import java.lang.reflect.Type; 35 import java.util.HashMap; 36 37 import jdk.vm.ci.common.JVMCIError; 38 import jdk.vm.ci.meta.JavaConstant; 39 import jdk.vm.ci.meta.JavaKind; 40 import jdk.vm.ci.meta.MetaAccessProvider; 41 import jdk.vm.ci.meta.ResolvedJavaField; 42 import jdk.vm.ci.meta.ResolvedJavaMethod; 43 import jdk.vm.ci.meta.ResolvedJavaType; 44 45 /** 46 * Implementation of {@link HotSpotJVMCIReflection} in terms of standard JDK reflection API. This is 47 * only available when running in the HotSpot heap. 48 */ 49 final class HotSpotJDKReflection extends HotSpotJVMCIReflection { 50 51 @Override 52 Object resolveObject(HotSpotObjectConstantImpl object) { 53 if (object == null) { 54 return null; 55 } 56 return ((DirectHotSpotObjectConstantImpl) object).object; 57 } 58 59 @Override 60 boolean isInstance(HotSpotResolvedObjectTypeImpl holder, HotSpotObjectConstantImpl obj) { 61 Class<?> javaMirror = getMirror(holder); 62 Object value = resolveObject(obj); 63 return javaMirror.isInstance(value); 64 } 65 66 @Override 67 boolean isAssignableFrom(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedObjectTypeImpl otherType) { 68 Class<?> javaMirror = getMirror(holder); 69 return javaMirror.isAssignableFrom(getMirror(otherType)); 70 71 } 72 73 @Override 74 Annotation[] getAnnotations(HotSpotResolvedObjectTypeImpl holder) { 75 Class<?> javaMirror = getMirror(holder); 76 return javaMirror.getAnnotations(); 77 } 78 79 @Override 80 Annotation[] getDeclaredAnnotations(HotSpotResolvedObjectTypeImpl holder) { 81 Class<?> javaMirror = getMirror(holder); 82 return javaMirror.getDeclaredAnnotations(); 83 } 84 85 @Override 86 <T extends Annotation> T getAnnotation(HotSpotResolvedObjectTypeImpl holder, Class<T> annotationClass) { 87 Class<?> javaMirror = getMirror(holder); 88 return javaMirror.getAnnotation(annotationClass); 89 } 90 91 @Override 92 boolean isLocalClass(HotSpotResolvedObjectTypeImpl holder) { 93 Class<?> javaMirror = getMirror(holder); 94 return javaMirror.isLocalClass(); 95 } 96 97 @Override 98 boolean isMemberClass(HotSpotResolvedObjectTypeImpl holder) { 99 Class<?> javaMirror = getMirror(holder); 100 return javaMirror.isMemberClass(); 101 } 102 103 @Override 104 HotSpotResolvedObjectType getEnclosingClass(HotSpotResolvedObjectTypeImpl holder) { 105 Class<?> javaMirror = getMirror(holder); 106 return (HotSpotResolvedObjectType) runtime().fromClass(javaMirror.getEnclosingClass()); 107 } 108 109 @Override 110 JavaConstant readFieldValue(HotSpotResolvedObjectTypeImpl holder, HotSpotResolvedJavaField field, boolean isVolatile) { 111 Class<?> javaMirror = getMirror(holder); 112 return readFieldValue(field, javaMirror, isVolatile); 113 } 114 115 @Override 116 JavaConstant readFieldValue(HotSpotObjectConstantImpl object, HotSpotResolvedJavaField field, boolean isVolatile) { 117 Object value = resolveObject(object); 118 return readFieldValue(field, value, isVolatile); 119 } 120 121 @Override 122 boolean equals(HotSpotObjectConstantImpl a, HotSpotObjectConstantImpl b) { 123 return resolveObject(a) == resolveObject(b) && a.isCompressed() == b.isCompressed(); 124 } 125 126 @Override 127 JavaConstant getJavaMirror(HotSpotResolvedPrimitiveType holder) { 128 return holder.mirror; 129 } 130 131 @Override 132 ResolvedJavaMethod.Parameter[] getParameters(HotSpotResolvedJavaMethodImpl javaMethod) { 133 java.lang.reflect.Parameter[] javaParameters = getMethod(javaMethod).getParameters(); 134 ResolvedJavaMethod.Parameter[] res = new ResolvedJavaMethod.Parameter[javaParameters.length]; 135 for (int i = 0; i < res.length; i++) { 136 java.lang.reflect.Parameter src = javaParameters[i]; 137 String paramName = src.isNamePresent() ? src.getName() : null; 138 res[i] = new ResolvedJavaMethod.Parameter(paramName, src.getModifiers(), javaMethod, i); 139 } 140 return res; 141 } 142 143 @Override 144 Annotation[][] getParameterAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { 145 return getMethod(javaMethod).getParameterAnnotations(); 146 } 147 148 @Override 149 Type[] getGenericParameterTypes(HotSpotResolvedJavaMethodImpl javaMethod) { 150 return getMethod(javaMethod).getGenericParameterTypes(); 151 } 152 153 @Override 154 Annotation[] getFieldAnnotations(HotSpotResolvedJavaFieldImpl javaField) { 155 return getField(javaField).getAnnotations(); 156 } 157 158 @Override 159 Annotation[] getMethodAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { 160 return getMethod(javaMethod).getAnnotations(); 161 } 162 163 @Override 164 Annotation[] getMethodDeclaredAnnotations(HotSpotResolvedJavaMethodImpl javaMethod) { 165 return getMethod(javaMethod).getDeclaredAnnotations(); 166 } 167 168 @Override 169 Annotation[] getFieldDeclaredAnnotations(HotSpotResolvedJavaFieldImpl javaField) { 170 return getField(javaField).getDeclaredAnnotations(); 171 } 172 173 @Override 174 <T extends Annotation> T getMethodAnnotation(HotSpotResolvedJavaMethodImpl javaMethod, Class<T> annotationClass) { 175 return getMethod(javaMethod).getAnnotation(annotationClass); 176 } 177 178 @Override 179 <T extends Annotation> T getFieldAnnotation(HotSpotResolvedJavaFieldImpl javaField, Class<T> annotationClass) { 180 return getField(javaField).getAnnotation(annotationClass); 181 } 182 183 @Override 184 HotSpotResolvedObjectTypeImpl getType(HotSpotObjectConstantImpl object) { 185 Object value = resolveObject(object); 186 Class<?> theClass = value.getClass(); 187 return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(theClass); 188 } 189 190 @Override 191 String asString(HotSpotObjectConstantImpl object) { 192 Object value = resolveObject(object); 193 if (value instanceof String) { 194 return (String) value; 195 } 196 return null; 197 } 198 199 @Override 200 ResolvedJavaType asJavaType(HotSpotObjectConstantImpl object) { 201 Object value = resolveObject(object); 202 if (value instanceof Class) { 203 Class<?> javaClass = (Class<?>) value; 204 return runtime().fromClass(javaClass); 205 } 206 if (value instanceof ResolvedJavaType) { 207 return (ResolvedJavaType) value; 208 } 209 return null; 210 } 211 212 @SuppressWarnings("unchecked") 213 @Override 214 <T> T asObject(HotSpotObjectConstantImpl object, Class<T> type) { 215 Object value = resolveObject(object); 216 if (type.isInstance(value)) { 217 return (T) value; 218 } 219 return null; 220 } 221 222 @Override 223 Object asObject(HotSpotObjectConstantImpl object, HotSpotResolvedJavaType type) { 224 Object value = resolveObject(object); 225 if (getMirror(type).isInstance(value)) { 226 return value; 227 } 228 return null; 229 } 230 231 @Override 232 String formatString(HotSpotObjectConstantImpl object) { 233 return JavaKind.Object.format(resolveObject(object)); 234 } 235 236 @Override 237 Integer getLength(HotSpotObjectConstantImpl arrayObject) { 238 Object object = resolveObject(arrayObject); 239 if (object.getClass().isArray()) { 240 return Array.getLength(object); 241 } 242 return null; 243 } 244 245 @Override 246 JavaConstant readArrayElement(HotSpotObjectConstantImpl arrayObject, int index) { 247 Object a = resolveObject(arrayObject); 248 if (!a.getClass().isArray() || index < 0 || index >= Array.getLength(a)) { 249 return null; 250 } 251 if (a instanceof Object[]) { 252 Object element = ((Object[]) a)[index]; 253 return forObject(element); 254 } else { 255 if (a instanceof int[]) { 256 return JavaConstant.forInt(((int[]) a)[index]); 257 } else if (a instanceof char[]) { 258 return JavaConstant.forChar(((char[]) a)[index]); 259 } else if (a instanceof byte[]) { 260 return JavaConstant.forByte(((byte[]) a)[index]); 261 } else if (a instanceof long[]) { 262 return JavaConstant.forLong(((long[]) a)[index]); 263 } else if (a instanceof short[]) { 264 return JavaConstant.forShort(((short[]) a)[index]); 265 } else if (a instanceof float[]) { 266 return JavaConstant.forFloat(((float[]) a)[index]); 267 } else if (a instanceof double[]) { 268 return JavaConstant.forDouble(((double[]) a)[index]); 269 } else if (a instanceof boolean[]) { 270 return JavaConstant.forBoolean(((boolean[]) a)[index]); 271 } else { 272 throw new JVMCIError("Should not reach here"); 273 } 274 } 275 } 276 277 @Override 278 JavaConstant unboxPrimitive(HotSpotObjectConstantImpl source) { 279 return JavaConstant.forBoxedPrimitive(resolveObject(source)); 280 } 281 282 @Override 283 JavaConstant forObject(Object value) { 284 if (value == null) { 285 return JavaConstant.NULL_POINTER; 286 } 287 return forNonNullObject(value); 288 } 289 290 private static HotSpotObjectConstantImpl forNonNullObject(Object value) { 291 return DirectHotSpotObjectConstantImpl.forNonNullObject(value, false); 292 } 293 294 @Override 295 JavaConstant boxPrimitive(JavaConstant source) { 296 return forNonNullObject(source.asBoxedPrimitive()); 297 } 298 299 @Override 300 int getInt(HotSpotObjectConstantImpl object, long displacement) { 301 return UNSAFE.getInt((resolveObject(object)), displacement); 302 } 303 304 @Override 305 byte getByte(HotSpotObjectConstantImpl object, long displacement) { 306 return UNSAFE.getByte(resolveObject(object), displacement); 307 } 308 309 @Override 310 short getShort(HotSpotObjectConstantImpl object, long displacement) { 311 return UNSAFE.getShort(resolveObject(object), displacement); 312 } 313 314 @Override 315 long getLong(HotSpotObjectConstantImpl object, long displacement) { 316 return UNSAFE.getLong(resolveObject(object), displacement); 317 } 318 319 @Override 320 void checkRead(HotSpotObjectConstantImpl constant, JavaKind kind, long displacement, HotSpotResolvedObjectType type) { 321 checkRead(kind, displacement, type, resolveObject(constant)); 322 } 323 324 /** 325 * Offset of injected {@code java.lang.Class::oop_size} field. No need to make {@code volatile} 326 * as initialization is idempotent. 327 */ 328 private long oopSizeOffset; 329 330 private static int computeOopSizeOffset(HotSpotJVMCIRuntime runtime) { 331 MetaAccessProvider metaAccess = runtime.getHostJVMCIBackend().getMetaAccess(); 332 ResolvedJavaType staticType = metaAccess.lookupJavaType(Class.class); 333 for (ResolvedJavaField f : staticType.getInstanceFields(false)) { 334 if (f.getName().equals("oop_size")) { 335 int offset = f.getOffset(); 336 assert offset != 0 : "not expecting offset of java.lang.Class::oop_size to be 0"; 337 return offset; 338 } 339 } 340 throw new JVMCIError("Could not find injected java.lang.Class::oop_size field"); 341 } 342 343 long oopSizeOffset() { 344 if (oopSizeOffset == 0) { 345 oopSizeOffset = computeOopSizeOffset(runtime()); 346 } 347 return oopSizeOffset; 348 } 349 350 private boolean checkRead(JavaKind kind, long displacement, HotSpotResolvedObjectType type, Object object) { 351 if (type.isArray()) { 352 ResolvedJavaType componentType = type.getComponentType(); 353 JavaKind componentKind = componentType.getJavaKind(); 354 final int headerSize = runtime().getArrayBaseOffset(componentKind); 355 int sizeOfElement = runtime().getArrayIndexScale(componentKind); 356 int length = Array.getLength(object); 357 long arrayEnd = headerSize + (sizeOfElement * length); 358 boolean aligned = ((displacement - headerSize) % sizeOfElement) == 0; 359 if (displacement < 0 || displacement > (arrayEnd - sizeOfElement) || (kind == JavaKind.Object && !aligned)) { 360 int index = (int) ((displacement - headerSize) / sizeOfElement); 361 throw new IllegalArgumentException("Unsafe array access: reading element of kind " + kind + 362 " at offset " + displacement + " (index ~ " + index + ") in " + 363 type.toJavaName() + " object of length " + length); 364 } 365 } else if (kind != JavaKind.Object) { 366 long size; 367 if (object instanceof Class) { 368 int wordSize = runtime().getHostJVMCIBackend().getCodeCache().getTarget().wordSize; 369 size = UNSAFE.getInt(object, oopSizeOffset()) * wordSize; 370 } else { 371 size = Math.abs(type.instanceSize()); 372 } 373 int bytesToRead = kind.getByteCount(); 374 if (displacement + bytesToRead > size || displacement < 0) { 375 throw new IllegalArgumentException("Unsafe access: reading " + bytesToRead + " bytes at offset " + displacement + " in " + 376 type.toJavaName() + " object of size " + size); 377 } 378 } else { 379 ResolvedJavaField field = null; 380 if (object instanceof Class) { 381 // Read of a static field 382 HotSpotResolvedJavaType hotSpotResolvedJavaType = runtime().fromClass((Class<?>) object); 383 if (hotSpotResolvedJavaType instanceof HotSpotResolvedObjectTypeImpl) { 384 HotSpotResolvedObjectTypeImpl staticFieldsHolder = (HotSpotResolvedObjectTypeImpl) hotSpotResolvedJavaType; 385 field = staticFieldsHolder.findStaticFieldWithOffset(displacement, JavaKind.Object); 386 } 387 } 388 if (field == null) { 389 field = type.findInstanceFieldWithOffset(displacement, JavaKind.Object); 390 } 391 if (field == null) { 392 throw new IllegalArgumentException("Unsafe object access: field not found for read of kind Object" + 393 " at offset " + displacement + " in " + type.toJavaName() + " object"); 394 } 395 if (field.getJavaKind() != JavaKind.Object) { 396 throw new IllegalArgumentException("Unsafe object access: field " + field.format("%H.%n:%T") + " not of expected kind Object" + 397 " at offset " + displacement + " in " + type.toJavaName() + " object"); 398 } 399 } 400 return true; 401 } 402 403 JavaConstant readFieldValue(HotSpotResolvedJavaField field, Object obj, boolean isVolatile) { 404 assert obj != null; 405 assert !field.isStatic() || obj instanceof Class; 406 long displacement = field.getOffset(); 407 408 assert checkRead(field.getJavaKind(), displacement, 409 (HotSpotResolvedObjectType) runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(field.isStatic() ? (Class<?>) obj : obj.getClass()), 410 obj); 411 JavaKind kind = field.getJavaKind(); 412 switch (kind) { 413 case Boolean: 414 return JavaConstant.forBoolean(isVolatile ? UNSAFE.getBooleanVolatile(obj, displacement) : UNSAFE.getBoolean(obj, displacement)); 415 case Byte: 416 return JavaConstant.forByte(isVolatile ? UNSAFE.getByteVolatile(obj, displacement) : UNSAFE.getByte(obj, displacement)); 417 case Char: 418 return JavaConstant.forChar(isVolatile ? UNSAFE.getCharVolatile(obj, displacement) : UNSAFE.getChar(obj, displacement)); 419 case Short: 420 return JavaConstant.forShort(isVolatile ? UNSAFE.getShortVolatile(obj, displacement) : UNSAFE.getShort(obj, displacement)); 421 case Int: 422 return JavaConstant.forInt(isVolatile ? UNSAFE.getIntVolatile(obj, displacement) : UNSAFE.getInt(obj, displacement)); 423 case Long: 424 return JavaConstant.forLong(isVolatile ? UNSAFE.getLongVolatile(obj, displacement) : UNSAFE.getLong(obj, displacement)); 425 case Float: 426 return JavaConstant.forFloat(isVolatile ? UNSAFE.getFloatVolatile(obj, displacement) : UNSAFE.getFloat(obj, displacement)); 427 case Double: 428 return JavaConstant.forDouble(isVolatile ? UNSAFE.getDoubleVolatile(obj, displacement) : UNSAFE.getDouble(obj, displacement)); 429 case Object: 430 return forObject(isVolatile ? UNSAFE.getReferenceVolatile(obj, displacement) : UNSAFE.getReference(obj, displacement)); 431 default: 432 throw new IllegalArgumentException("Unsupported kind: " + kind); 433 434 } 435 } 436 437 /** 438 * Gets a {@link Method} object corresponding to {@code method}. This method guarantees the same 439 * {@link Method} object is returned if called twice on the same {@code method} value. 440 */ 441 private static Executable getMethod(HotSpotResolvedJavaMethodImpl method) { 442 assert !method.isClassInitializer() : method; 443 if (method.toJavaCache == null) { 444 synchronized (method) { 445 if (method.toJavaCache == null) { 446 method.toJavaCache = compilerToVM().asReflectionExecutable(method); 447 } 448 } 449 } 450 return method.toJavaCache; 451 } 452 453 /** 454 * Gets a {@link Field} object corresponding to {@code field}. This method guarantees the same 455 * {@link Field} object is returned if called twice on the same {@code field} value. This is 456 * required to ensure the results of {@link HotSpotResolvedJavaFieldImpl#getAnnotations()} and 457 * {@link HotSpotResolvedJavaFieldImpl#getAnnotation(Class)} are stable (i.e., for a given field 458 * {@code f} and annotation class {@code a}, the same object is returned for each call to 459 * {@code f.getAnnotation(a)}). 460 */ 461 private static Field getField(HotSpotResolvedJavaFieldImpl field) { 462 HotSpotResolvedObjectTypeImpl declaringClass = field.getDeclaringClass(); 463 synchronized (declaringClass) { 464 HashMap<HotSpotResolvedJavaFieldImpl, Field> cache = declaringClass.reflectionFieldCache; 465 if (cache == null) { 466 cache = new HashMap<>(); 467 declaringClass.reflectionFieldCache = cache; 468 } 469 Field reflect = cache.get(field); 470 if (reflect == null) { 471 reflect = compilerToVM().asReflectionField(field.getDeclaringClass(), field.getIndex()); 472 cache.put(field, reflect); 473 } 474 return reflect; 475 } 476 } 477 478 Class<?> getMirror(HotSpotResolvedObjectTypeImpl holder) { 479 return (Class<?>) resolveObject((HotSpotObjectConstantImpl) holder.getJavaMirror()); 480 } 481 482 Class<?> getMirror(HotSpotResolvedJavaType type) { 483 assert type != null; 484 if (type instanceof HotSpotResolvedPrimitiveType) { 485 return (Class<?>) resolveObject(((HotSpotResolvedPrimitiveType) type).mirror); 486 } else { 487 return getMirror((HotSpotResolvedObjectTypeImpl) type); 488 } 489 } 490 } 491