1 /* 2 * Copyright (c) 2011, 2017, 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 java.util.Objects.requireNonNull; 26 import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; 27 import static jdk.vm.ci.hotspot.HotSpotConstantPool.isSignaturePolymorphicHolder; 28 import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; 29 import static jdk.vm.ci.hotspot.HotSpotModifiers.jvmClassModifiers; 30 import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; 31 import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 32 33 import java.lang.annotation.Annotation; 34 import java.lang.reflect.Array; 35 import java.lang.reflect.Constructor; 36 import java.lang.reflect.Method; 37 import java.lang.reflect.Modifier; 38 import java.nio.ByteOrder; 39 import java.util.HashMap; 40 41 import jdk.vm.ci.common.JVMCIError; 42 import jdk.vm.ci.meta.Assumptions.AssumptionResult; 43 import jdk.vm.ci.meta.Assumptions.ConcreteMethod; 44 import jdk.vm.ci.meta.Assumptions.ConcreteSubtype; 45 import jdk.vm.ci.meta.Assumptions.LeafType; 46 import jdk.vm.ci.meta.Assumptions.NoFinalizableSubclass; 47 import jdk.vm.ci.meta.Constant; 48 import jdk.vm.ci.meta.JavaConstant; 49 import jdk.vm.ci.meta.JavaKind; 50 import jdk.vm.ci.meta.JavaType; 51 import jdk.vm.ci.meta.ResolvedJavaField; 52 import jdk.vm.ci.meta.ResolvedJavaMethod; 53 import jdk.vm.ci.meta.ResolvedJavaType; 54 import jdk.vm.ci.meta.UnresolvedJavaField; 55 import jdk.vm.ci.meta.UnresolvedJavaType; 56 57 /** 58 * Implementation of {@link JavaType} for resolved non-primitive HotSpot classes. 59 */ 60 final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implements HotSpotResolvedObjectType, MetaspaceWrapperObject { 61 62 private static final HotSpotResolvedJavaField[] NO_FIELDS = new HotSpotResolvedJavaField[0]; 63 private static final int METHOD_CACHE_ARRAY_CAPACITY = 8; 64 65 /** 66 * The Java class this type represents. 67 */ 68 private final Class<?> javaClass; 69 private HotSpotResolvedJavaMethodImpl[] methodCacheArray; 70 private HashMap<Long, HotSpotResolvedJavaMethodImpl> methodCacheHashMap; 71 private HotSpotResolvedJavaField[] instanceFields; 72 private HotSpotResolvedObjectTypeImpl[] interfaces; 73 private HotSpotConstantPool constantPool; 74 final HotSpotJVMCIMetaAccessContext context; 75 private HotSpotResolvedObjectType arrayOfType; 76 77 /** 78 * Gets the JVMCI mirror for a {@link Class} object. 79 * 80 * @return the {@link HotSpotResolvedJavaType} corresponding to {@code javaClass} 81 */ fromObjectClass(Class<?> javaClass)82 static HotSpotResolvedObjectTypeImpl fromObjectClass(Class<?> javaClass) { 83 return (HotSpotResolvedObjectTypeImpl) runtime().fromClass(javaClass); 84 } 85 86 /** 87 * Gets the JVMCI mirror from a HotSpot type. Since {@link Class} is already a proxy for the 88 * underlying Klass*, it is used instead of the raw Klass*. 89 * 90 * Called from the VM. 91 * 92 * @param javaClass a {@link Class} object 93 * @return the {@link ResolvedJavaType} corresponding to {@code javaClass} 94 */ 95 @SuppressWarnings("unused") fromMetaspace(Class<?> javaClass)96 private static HotSpotResolvedObjectTypeImpl fromMetaspace(Class<?> javaClass) { 97 return fromObjectClass(javaClass); 98 } 99 100 /** 101 * Creates the JVMCI mirror for a {@link Class} object. 102 * 103 * <p> 104 * <b>NOTE</b>: Creating an instance of this class does not install the mirror for the 105 * {@link Class} type. Use {@link #fromObjectClass(Class)} or {@link #fromMetaspace(Class)} 106 * instead. 107 * </p> 108 * 109 * @param javaClass the Class to create the mirror for 110 * @param context 111 */ HotSpotResolvedObjectTypeImpl(Class<?> javaClass, HotSpotJVMCIMetaAccessContext context)112 HotSpotResolvedObjectTypeImpl(Class<?> javaClass, HotSpotJVMCIMetaAccessContext context) { 113 super(getSignatureName(javaClass)); 114 this.javaClass = javaClass; 115 this.context = context; 116 assert getName().charAt(0) != '[' || isArray() : getName(); 117 } 118 119 /** 120 * Returns the name of this type as it would appear in a signature. 121 */ getSignatureName(Class<?> javaClass)122 private static String getSignatureName(Class<?> javaClass) { 123 if (javaClass.isArray()) { 124 return javaClass.getName().replace('.', '/'); 125 } 126 return "L" + javaClass.getName().replace('.', '/') + ";"; 127 } 128 129 /** 130 * Gets the metaspace Klass for this type. 131 */ getMetaspaceKlass()132 long getMetaspaceKlass() { 133 if (HotSpotJVMCIRuntime.getHostWordKind() == JavaKind.Long) { 134 return UNSAFE.getLong(javaClass, config().klassOffset); 135 } 136 return UNSAFE.getInt(javaClass, config().klassOffset) & 0xFFFFFFFFL; 137 } 138 139 @Override getMetaspacePointer()140 public long getMetaspacePointer() { 141 return getMetaspaceKlass(); 142 } 143 144 /** 145 * The Klass* for this object is kept alive by the direct reference to {@link #javaClass} so no 146 * extra work is required. 147 */ 148 @Override isRegistered()149 public boolean isRegistered() { 150 return true; 151 } 152 153 @Override getModifiers()154 public int getModifiers() { 155 if (isArray()) { 156 return (getElementalType().getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED)) | Modifier.FINAL | Modifier.ABSTRACT; 157 } else { 158 return getAccessFlags() & jvmClassModifiers(); 159 } 160 } 161 getAccessFlags()162 public int getAccessFlags() { 163 HotSpotVMConfig config = config(); 164 return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); 165 } 166 167 @Override getArrayClass()168 public HotSpotResolvedObjectType getArrayClass() { 169 if (arrayOfType == null) { 170 arrayOfType = fromObjectClass(Array.newInstance(mirror(), 0).getClass()); 171 } 172 return arrayOfType; 173 } 174 175 @Override getComponentType()176 public ResolvedJavaType getComponentType() { 177 Class<?> javaComponentType = mirror().getComponentType(); 178 return javaComponentType == null ? null : runtime().fromClass(javaComponentType); 179 } 180 181 @Override findLeafConcreteSubtype()182 public AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() { 183 if (isLeaf()) { 184 // No assumptions are required. 185 return new AssumptionResult<>(this); 186 } 187 HotSpotVMConfig config = config(); 188 if (isArray()) { 189 ResolvedJavaType elementalType = getElementalType(); 190 AssumptionResult<ResolvedJavaType> elementType = elementalType.findLeafConcreteSubtype(); 191 if (elementType != null && elementType.getResult().equals(elementalType)) { 192 /* 193 * If the elementType is leaf then the array is leaf under the same assumptions but 194 * only if the element type is exactly the leaf type. The element type can be 195 * abstract even if there is only one implementor of the abstract type. 196 */ 197 AssumptionResult<ResolvedJavaType> result = new AssumptionResult<>(this); 198 result.add(elementType); 199 return result; 200 } 201 return null; 202 } else if (isInterface()) { 203 HotSpotResolvedObjectTypeImpl implementor = getSingleImplementor(); 204 /* 205 * If the implementor field contains itself that indicates that the interface has more 206 * than one implementors (see: InstanceKlass::add_implementor). 207 */ 208 if (implementor == null || implementor.equals(this)) { 209 return null; 210 } 211 212 assert !implementor.isInterface(); 213 if (implementor.isAbstract() || !implementor.isLeafClass()) { 214 AssumptionResult<ResolvedJavaType> leafConcreteSubtype = implementor.findLeafConcreteSubtype(); 215 if (leafConcreteSubtype != null) { 216 assert !leafConcreteSubtype.getResult().equals(implementor); 217 AssumptionResult<ResolvedJavaType> newResult = new AssumptionResult<>(leafConcreteSubtype.getResult(), new ConcreteSubtype(this, implementor)); 218 // Accumulate leaf assumptions and return the combined result. 219 newResult.add(leafConcreteSubtype); 220 return newResult; 221 } 222 return null; 223 } 224 return concreteSubtype(implementor); 225 } else { 226 HotSpotResolvedObjectTypeImpl type = this; 227 while (type.isAbstract()) { 228 HotSpotResolvedObjectTypeImpl subklass = type.getSubklass(); 229 if (subklass == null || UNSAFE.getAddress(subklass.getMetaspaceKlass() + config.nextSiblingOffset) != 0) { 230 return null; 231 } 232 type = subklass; 233 } 234 if (type.isAbstract() || type.isInterface() || !type.isLeafClass()) { 235 return null; 236 } 237 if (this.isAbstract()) { 238 return concreteSubtype(type); 239 } else { 240 assert this.equals(type); 241 return new AssumptionResult<>(type, new LeafType(type)); 242 } 243 } 244 } 245 concreteSubtype(HotSpotResolvedObjectTypeImpl type)246 private AssumptionResult<ResolvedJavaType> concreteSubtype(HotSpotResolvedObjectTypeImpl type) { 247 if (type.isLeaf()) { 248 return new AssumptionResult<>(type, new ConcreteSubtype(this, type)); 249 } else { 250 return new AssumptionResult<>(type, new LeafType(type), new ConcreteSubtype(this, type)); 251 } 252 } 253 254 /** 255 * Returns if type {@code type} is a leaf class. This is the case if the 256 * {@code Klass::_subklass} field of the underlying class is zero. 257 * 258 * @return true if the type is a leaf class 259 */ isLeafClass()260 private boolean isLeafClass() { 261 return UNSAFE.getLong(this.getMetaspaceKlass() + config().subklassOffset) == 0; 262 } 263 264 /** 265 * Returns the {@code Klass::_subklass} field of the underlying metaspace klass for the given 266 * type {@code type}. 267 * 268 * @return value of the subklass field as metaspace klass pointer 269 */ getSubklass()270 private HotSpotResolvedObjectTypeImpl getSubklass() { 271 return compilerToVM().getResolvedJavaType(this, config().subklassOffset, false); 272 } 273 274 @Override getSuperclass()275 public HotSpotResolvedObjectTypeImpl getSuperclass() { 276 Class<?> javaSuperclass = mirror().getSuperclass(); 277 return javaSuperclass == null ? null : fromObjectClass(javaSuperclass); 278 } 279 280 @Override getInterfaces()281 public HotSpotResolvedObjectTypeImpl[] getInterfaces() { 282 if (interfaces == null) { 283 Class<?>[] javaInterfaces = mirror().getInterfaces(); 284 HotSpotResolvedObjectTypeImpl[] result = new HotSpotResolvedObjectTypeImpl[javaInterfaces.length]; 285 for (int i = 0; i < javaInterfaces.length; i++) { 286 result[i] = fromObjectClass(javaInterfaces[i]); 287 } 288 interfaces = result; 289 } 290 return interfaces; 291 } 292 293 @Override getSingleImplementor()294 public HotSpotResolvedObjectTypeImpl getSingleImplementor() { 295 if (!isInterface()) { 296 throw new JVMCIError("Cannot call getSingleImplementor() on a non-interface type: %s", this); 297 } 298 return compilerToVM().getImplementor(this); 299 } 300 301 @Override getSupertype()302 public HotSpotResolvedObjectTypeImpl getSupertype() { 303 if (isArray()) { 304 ResolvedJavaType componentType = getComponentType(); 305 if (mirror() == Object[].class || componentType.isPrimitive()) { 306 return fromObjectClass(Object.class); 307 } 308 return (HotSpotResolvedObjectTypeImpl) ((HotSpotResolvedObjectTypeImpl) componentType).getSupertype().getArrayClass(); 309 } 310 if (isInterface()) { 311 return fromObjectClass(Object.class); 312 } 313 return getSuperclass(); 314 } 315 316 @Override findLeastCommonAncestor(ResolvedJavaType otherType)317 public HotSpotResolvedObjectType findLeastCommonAncestor(ResolvedJavaType otherType) { 318 if (otherType.isPrimitive()) { 319 return null; 320 } else { 321 HotSpotResolvedObjectTypeImpl t1 = this; 322 HotSpotResolvedObjectTypeImpl t2 = (HotSpotResolvedObjectTypeImpl) otherType; 323 while (true) { 324 if (t1.isAssignableFrom(t2)) { 325 return t1; 326 } 327 if (t2.isAssignableFrom(t1)) { 328 return t2; 329 } 330 t1 = t1.getSupertype(); 331 t2 = t2.getSupertype(); 332 } 333 } 334 } 335 336 @Override hasFinalizableSubclass()337 public AssumptionResult<Boolean> hasFinalizableSubclass() { 338 assert !isArray(); 339 if (!compilerToVM().hasFinalizableSubclass(this)) { 340 return new AssumptionResult<>(false, new NoFinalizableSubclass(this)); 341 } 342 return new AssumptionResult<>(true); 343 } 344 345 @Override hasFinalizer()346 public boolean hasFinalizer() { 347 return (getAccessFlags() & config().jvmAccHasFinalizer) != 0; 348 } 349 350 @Override isPrimitive()351 public boolean isPrimitive() { 352 return false; 353 } 354 355 @Override isArray()356 public boolean isArray() { 357 return mirror().isArray(); 358 } 359 360 @Override isEnum()361 public boolean isEnum() { 362 return mirror().isEnum(); 363 } 364 365 @Override isInitialized()366 public boolean isInitialized() { 367 return isArray() ? true : getInitState() == config().instanceKlassStateFullyInitialized; 368 } 369 370 @Override isLinked()371 public boolean isLinked() { 372 return isArray() ? true : getInitState() >= config().instanceKlassStateLinked; 373 } 374 375 @Override link()376 public void link() { 377 if (!isLinked()) { 378 runtime().compilerToVm.ensureLinked(this); 379 } 380 } 381 382 @Override hasDefaultMethods()383 public boolean hasDefaultMethods() { 384 HotSpotVMConfig config = config(); 385 int miscFlags = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassMiscFlagsOffset); 386 return (miscFlags & config.jvmMiscFlagsHasDefaultMethods) != 0; 387 } 388 389 @Override declaresDefaultMethods()390 public boolean declaresDefaultMethods() { 391 HotSpotVMConfig config = config(); 392 int miscFlags = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassMiscFlagsOffset); 393 return (miscFlags & config.jvmMiscFlagsDeclaresDefaultMethods) != 0; 394 } 395 396 /** 397 * Returns the value of the state field {@code InstanceKlass::_init_state} of the metaspace 398 * klass. 399 * 400 * @return state field value of this type 401 */ getInitState()402 private int getInitState() { 403 assert !isArray() : "_init_state only exists in InstanceKlass"; 404 return UNSAFE.getByte(getMetaspaceKlass() + config().instanceKlassInitStateOffset) & 0xFF; 405 } 406 407 @Override initialize()408 public void initialize() { 409 if (!isInitialized()) { 410 UNSAFE.ensureClassInitialized(mirror()); 411 assert isInitialized(); 412 } 413 } 414 415 @Override isInstance(JavaConstant obj)416 public boolean isInstance(JavaConstant obj) { 417 if (obj.getJavaKind() == JavaKind.Object && !obj.isNull()) { 418 return mirror().isInstance(((HotSpotObjectConstantImpl) obj).object()); 419 } 420 return false; 421 } 422 423 @Override isInstanceClass()424 public boolean isInstanceClass() { 425 return !isArray() && !isInterface(); 426 } 427 428 @Override isInterface()429 public boolean isInterface() { 430 return mirror().isInterface(); 431 } 432 433 @Override isAssignableFrom(ResolvedJavaType other)434 public boolean isAssignableFrom(ResolvedJavaType other) { 435 assert other != null; 436 if (other instanceof HotSpotResolvedObjectTypeImpl) { 437 HotSpotResolvedObjectTypeImpl otherType = (HotSpotResolvedObjectTypeImpl) other; 438 return mirror().isAssignableFrom(otherType.mirror()); 439 } 440 return false; 441 } 442 443 @Override getHostClass()444 public ResolvedJavaType getHostClass() { 445 if (isArray()) { 446 return null; 447 } 448 return compilerToVM().getHostClass(this); 449 } 450 451 @Override isJavaLangObject()452 public boolean isJavaLangObject() { 453 return javaClass.equals(Object.class); 454 } 455 456 @Override getJavaKind()457 public JavaKind getJavaKind() { 458 return JavaKind.Object; 459 } 460 461 @Override resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType)462 public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { 463 assert !callerType.isArray(); 464 if (isInterface()) { 465 // Methods can only be resolved against concrete types 466 return null; 467 } 468 if (method.isConcrete() && method.getDeclaringClass().equals(this) && method.isPublic() && !isSignaturePolymorphicHolder(method.getDeclaringClass())) { 469 return method; 470 } 471 if (!method.getDeclaringClass().isAssignableFrom(this)) { 472 return null; 473 } 474 HotSpotResolvedJavaMethodImpl hotSpotMethod = (HotSpotResolvedJavaMethodImpl) method; 475 HotSpotResolvedObjectTypeImpl hotSpotCallerType = (HotSpotResolvedObjectTypeImpl) callerType; 476 return compilerToVM().resolveMethod(this, hotSpotMethod, hotSpotCallerType); 477 } 478 479 @Override getConstantPool()480 public HotSpotConstantPool getConstantPool() { 481 if (constantPool == null || !isArray() && UNSAFE.getAddress(getMetaspaceKlass() + config().instanceKlassConstantsOffset) != constantPool.getMetaspaceConstantPool()) { 482 /* 483 * If the pointer to the ConstantPool has changed since this was last read refresh the 484 * HotSpotConstantPool wrapper object. This ensures that uses of the constant pool are 485 * operating on the latest one and that HotSpotResolvedJavaMethodImpls will be able to 486 * use the shared copy instead of creating their own instance. 487 */ 488 constantPool = compilerToVM().getConstantPool(this); 489 } 490 return constantPool; 491 } 492 493 /** 494 * Gets the instance size of this type. If an instance of this type cannot be fast path 495 * allocated, then the returned value is negative (its absolute value gives the size). Must not 496 * be called if this is an array or interface type. 497 */ 498 @Override instanceSize()499 public int instanceSize() { 500 assert !isArray(); 501 assert !isInterface(); 502 503 HotSpotVMConfig config = config(); 504 final int layoutHelper = layoutHelper(); 505 assert layoutHelper > config.klassLayoutHelperNeutralValue : "must be instance"; 506 507 // See: Klass::layout_helper_size_in_bytes 508 int size = layoutHelper & ~config.klassLayoutHelperInstanceSlowPathBit; 509 510 // See: Klass::layout_helper_needs_slow_path 511 boolean needsSlowPath = (layoutHelper & config.klassLayoutHelperInstanceSlowPathBit) != 0; 512 513 return needsSlowPath ? -size : size; 514 } 515 516 @Override layoutHelper()517 public int layoutHelper() { 518 HotSpotVMConfig config = config(); 519 return UNSAFE.getInt(getMetaspaceKlass() + config.klassLayoutHelperOffset); 520 } 521 522 @Override getFingerprint()523 public long getFingerprint() { 524 return compilerToVM().getFingerprint(getMetaspaceKlass()); 525 } 526 createMethod(long metaspaceMethod)527 synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { 528 // Maintain cache as array. 529 if (methodCacheArray == null) { 530 methodCacheArray = new HotSpotResolvedJavaMethodImpl[METHOD_CACHE_ARRAY_CAPACITY]; 531 } 532 533 int i = 0; 534 for (; i < methodCacheArray.length; ++i) { 535 HotSpotResolvedJavaMethodImpl curMethod = methodCacheArray[i]; 536 if (curMethod == null) { 537 HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); 538 methodCacheArray[i] = newMethod; 539 context.add(newMethod); 540 return newMethod; 541 } else if (curMethod.getMetaspacePointer() == metaspaceMethod) { 542 return curMethod; 543 } 544 } 545 546 // Fall-back to hash table. 547 if (methodCacheHashMap == null) { 548 methodCacheHashMap = new HashMap<>(); 549 } 550 551 HotSpotResolvedJavaMethodImpl lookupResult = methodCacheHashMap.get(metaspaceMethod); 552 if (lookupResult == null) { 553 HotSpotResolvedJavaMethodImpl newMethod = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); 554 methodCacheHashMap.put(metaspaceMethod, newMethod); 555 context.add(lookupResult); 556 return newMethod; 557 } else { 558 return lookupResult; 559 } 560 } 561 562 @Override getVtableLength()563 public int getVtableLength() { 564 HotSpotVMConfig config = config(); 565 if (isInterface() || isArray()) { 566 /* Everything has the core vtable of java.lang.Object */ 567 return config.baseVtableLength(); 568 } 569 int result = UNSAFE.getInt(getMetaspaceKlass() + config.klassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize); 570 assert result >= config.baseVtableLength() : UNSAFE.getInt(getMetaspaceKlass() + config.klassVtableLengthOffset) + " " + config.vtableEntrySize; 571 return result; 572 } 573 createField(JavaType type, long offset, int rawFlags, int index)574 HotSpotResolvedJavaField createField(JavaType type, long offset, int rawFlags, int index) { 575 return new HotSpotResolvedJavaFieldImpl(this, type, offset, rawFlags, index); 576 } 577 578 @Override findUniqueConcreteMethod(ResolvedJavaMethod method)579 public AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) { 580 HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method; 581 HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass(); 582 /* 583 * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared 584 * holder, usually because of phis, so make sure that the type is related to the declared 585 * type before using it for lookup. Unlinked types should also be ignored because we can't 586 * resolve the proper method to invoke. Generally unlinked types in invokes should result in 587 * a deopt instead since they can't really be used if they aren't linked yet. 588 */ 589 if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) { 590 ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder); 591 if (result != null) { 592 return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result)); 593 } 594 return null; 595 } 596 /* 597 * The holder may be a subtype of the declaredHolder so make sure to resolve the method to 598 * the correct method for the subtype. 599 */ 600 HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this); 601 if (resolvedMethod == null) { 602 // The type isn't known to implement the method. 603 return null; 604 } 605 if (resolvedMethod.canBeStaticallyBound()) { 606 // No assumptions are required. 607 return new AssumptionResult<>(resolvedMethod); 608 } 609 610 ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this); 611 if (result != null) { 612 return new AssumptionResult<>(result, new ConcreteMethod(method, this, result)); 613 } 614 return null; 615 } 616 createFieldInfo(int index)617 FieldInfo createFieldInfo(int index) { 618 return new FieldInfo(index); 619 } 620 621 /** 622 * This class represents the field information for one field contained in the fields array of an 623 * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. 624 */ 625 class FieldInfo { 626 /** 627 * Native pointer into the array of Java shorts. 628 */ 629 private final long metaspaceData; 630 631 /** 632 * Creates a field info for the field in the fields array at index {@code index}. 633 * 634 * @param index index to the fields array 635 */ FieldInfo(int index)636 FieldInfo(int index) { 637 HotSpotVMConfig config = config(); 638 // Get Klass::_fields 639 final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); 640 assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; 641 int offset = config.fieldInfoFieldSlots * Short.BYTES * index; 642 metaspaceData = metaspaceFields + config.arrayU2DataOffset + offset; 643 } 644 getAccessFlags()645 private int getAccessFlags() { 646 return readFieldSlot(config().fieldInfoAccessFlagsOffset); 647 } 648 getNameIndex()649 private int getNameIndex() { 650 return readFieldSlot(config().fieldInfoNameIndexOffset); 651 } 652 getSignatureIndex()653 private int getSignatureIndex() { 654 return readFieldSlot(config().fieldInfoSignatureIndexOffset); 655 } 656 getOffset()657 public int getOffset() { 658 HotSpotVMConfig config = config(); 659 final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); 660 final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); 661 final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; 662 return offset; 663 } 664 665 /** 666 * Helper method to read an entry (slot) from the field array. Currently field info is laid 667 * on top an array of Java shorts. 668 */ readFieldSlot(int index)669 private int readFieldSlot(int index) { 670 int offset = Short.BYTES * index; 671 return UNSAFE.getChar(metaspaceData + offset); 672 } 673 674 /** 675 * Returns the name of this field as a {@link String}. If the field is an internal field the 676 * name index is pointing into the vmSymbols table. 677 */ getName()678 public String getName() { 679 final int nameIndex = getNameIndex(); 680 return isInternal() ? config().symbolAt(nameIndex) : getConstantPool().lookupUtf8(nameIndex); 681 } 682 683 /** 684 * Returns the signature of this field as {@link String}. If the field is an internal field 685 * the signature index is pointing into the vmSymbols table. 686 */ getSignature()687 public String getSignature() { 688 final int signatureIndex = getSignatureIndex(); 689 return isInternal() ? config().symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex); 690 } 691 getType()692 public JavaType getType() { 693 String signature = getSignature(); 694 return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false); 695 } 696 isInternal()697 private boolean isInternal() { 698 return (getAccessFlags() & config().jvmAccFieldInternal) != 0; 699 } 700 isStatic()701 public boolean isStatic() { 702 return Modifier.isStatic(getAccessFlags()); 703 } 704 hasGenericSignature()705 public boolean hasGenericSignature() { 706 return (getAccessFlags() & config().jvmAccFieldHasGenericSignature) != 0; 707 } 708 } 709 710 @Override getInstanceFields(boolean includeSuperclasses)711 public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { 712 if (instanceFields == null) { 713 if (isArray() || isInterface()) { 714 instanceFields = NO_FIELDS; 715 } else { 716 HotSpotResolvedJavaField[] prepend = NO_FIELDS; 717 if (getSuperclass() != null) { 718 prepend = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); 719 } 720 instanceFields = getFields(false, prepend); 721 } 722 } 723 if (!includeSuperclasses && getSuperclass() != null) { 724 int superClassFieldCount = getSuperclass().getInstanceFields(true).length; 725 if (superClassFieldCount == instanceFields.length) { 726 // This class does not have any instance fields of its own. 727 return NO_FIELDS; 728 } else if (superClassFieldCount != 0) { 729 HotSpotResolvedJavaField[] result = new HotSpotResolvedJavaField[instanceFields.length - superClassFieldCount]; 730 System.arraycopy(instanceFields, superClassFieldCount, result, 0, result.length); 731 return result; 732 } else { 733 // The super classes of this class do not have any instance fields. 734 } 735 } 736 return instanceFields; 737 } 738 739 @Override getStaticFields()740 public ResolvedJavaField[] getStaticFields() { 741 if (isArray()) { 742 return new HotSpotResolvedJavaField[0]; 743 } else { 744 return getFields(true, NO_FIELDS); 745 } 746 } 747 748 /** 749 * Gets the instance or static fields of this class. 750 * 751 * @param retrieveStaticFields specifies whether to return instance or static fields 752 * @param prepend an array to be prepended to the returned result 753 */ getFields(boolean retrieveStaticFields, HotSpotResolvedJavaField[] prepend)754 private HotSpotResolvedJavaField[] getFields(boolean retrieveStaticFields, HotSpotResolvedJavaField[] prepend) { 755 HotSpotVMConfig config = config(); 756 final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); 757 int metaspaceFieldsLength = UNSAFE.getInt(metaspaceFields + config.arrayU1LengthOffset); 758 int resultCount = 0; 759 int index = 0; 760 for (int i = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { 761 FieldInfo field = new FieldInfo(index); 762 if (field.hasGenericSignature()) { 763 metaspaceFieldsLength--; 764 } 765 766 if (field.isStatic() == retrieveStaticFields) { 767 resultCount++; 768 } 769 } 770 771 if (resultCount == 0) { 772 return prepend; 773 } 774 775 int prependLength = prepend.length; 776 resultCount += prependLength; 777 778 HotSpotResolvedJavaField[] result = new HotSpotResolvedJavaField[resultCount]; 779 if (prependLength != 0) { 780 System.arraycopy(prepend, 0, result, 0, prependLength); 781 } 782 783 int resultIndex = prependLength; 784 for (int i = 0; i < index; ++i) { 785 FieldInfo field = new FieldInfo(i); 786 if (field.isStatic() == retrieveStaticFields) { 787 int offset = field.getOffset(); 788 HotSpotResolvedJavaField resolvedJavaField = createField(field.getType(), offset, field.getAccessFlags(), i); 789 790 // Make sure the result is sorted by offset. 791 int j; 792 for (j = resultIndex - 1; j >= prependLength && result[j].getOffset() > offset; j--) { 793 result[j + 1] = result[j]; 794 } 795 result[j + 1] = resolvedJavaField; 796 resultIndex++; 797 } 798 } 799 800 return result; 801 } 802 803 @Override mirror()804 public Class<?> mirror() { 805 return javaClass; 806 } 807 808 @Override getSourceFileName()809 public String getSourceFileName() { 810 HotSpotVMConfig config = config(); 811 final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); 812 if (sourceFileNameIndex == 0) { 813 return null; 814 } 815 return getConstantPool().lookupUtf8(sourceFileNameIndex); 816 } 817 818 @Override getAnnotations()819 public Annotation[] getAnnotations() { 820 return mirror().getAnnotations(); 821 } 822 823 @Override getDeclaredAnnotations()824 public Annotation[] getDeclaredAnnotations() { 825 return mirror().getDeclaredAnnotations(); 826 } 827 828 @Override getAnnotation(Class<T> annotationClass)829 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 830 return mirror().getAnnotation(annotationClass); 831 } 832 833 /** 834 * Performs a fast-path check that this type is resolved in the context of a given accessing 835 * class. A negative result does not mean this type is not resolved with respect to 836 * {@code accessingClass}. That can only be determined by 837 * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) 838 * re-resolving} the type. 839 */ 840 @Override isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass)841 public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) { 842 assert accessingClass != null; 843 ResolvedJavaType elementType = getElementalType(); 844 if (elementType.isPrimitive()) { 845 // Primitive type resolution is context free. 846 return true; 847 } 848 if (elementType.getName().startsWith("Ljava/")) { 849 // Classes in a java.* package can only be defined by the 850 // boot or platform class loader. 851 return true; 852 } 853 ClassLoader thisCl = mirror().getClassLoader(); 854 ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader(); 855 return thisCl == accessingClassCl; 856 } 857 858 @Override resolve(ResolvedJavaType accessingClass)859 public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { 860 if (isDefinitelyResolvedWithRespectTo(requireNonNull(accessingClass))) { 861 return this; 862 } 863 HotSpotResolvedObjectTypeImpl accessingType = (HotSpotResolvedObjectTypeImpl) accessingClass; 864 return (ResolvedJavaType) runtime().lookupType(getName(), accessingType, true); 865 } 866 867 /** 868 * Gets the metaspace Klass boxed in a {@link JavaConstant}. 869 */ 870 @Override klass()871 public Constant klass() { 872 return HotSpotMetaspaceConstantImpl.forMetaspaceObject(this, false); 873 } 874 875 @Override isPrimaryType()876 public boolean isPrimaryType() { 877 return config().secondarySuperCacheOffset != superCheckOffset(); 878 } 879 880 @Override superCheckOffset()881 public int superCheckOffset() { 882 HotSpotVMConfig config = config(); 883 return UNSAFE.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset); 884 } 885 886 @Override prototypeMarkWord()887 public long prototypeMarkWord() { 888 HotSpotVMConfig config = config(); 889 if (isArray()) { 890 return config.arrayPrototypeMarkWord(); 891 } else { 892 return UNSAFE.getAddress(getMetaspaceKlass() + config.prototypeMarkWordOffset); 893 } 894 } 895 896 @Override findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind)897 public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind) { 898 ResolvedJavaField[] declaredFields = getInstanceFields(true); 899 return findFieldWithOffset(offset, expectedEntryKind, declaredFields); 900 } 901 findStaticFieldWithOffset(long offset, JavaKind expectedEntryKind)902 public ResolvedJavaField findStaticFieldWithOffset(long offset, JavaKind expectedEntryKind) { 903 ResolvedJavaField[] declaredFields = getStaticFields(); 904 return findFieldWithOffset(offset, expectedEntryKind, declaredFields); 905 } 906 findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields)907 private static ResolvedJavaField findFieldWithOffset(long offset, JavaKind expectedEntryKind, ResolvedJavaField[] declaredFields) { 908 for (ResolvedJavaField field : declaredFields) { 909 HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field; 910 long resolvedFieldOffset = resolvedField.getOffset(); 911 // @formatter:off 912 if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && 913 expectedEntryKind.isPrimitive() && 914 !expectedEntryKind.equals(JavaKind.Void) && 915 resolvedField.getJavaKind().isPrimitive()) { 916 resolvedFieldOffset += 917 resolvedField.getJavaKind().getByteCount() - 918 Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); 919 } 920 if (resolvedFieldOffset == offset) { 921 return field; 922 } 923 // @formatter:on 924 } 925 return null; 926 } 927 928 @Override isLocal()929 public boolean isLocal() { 930 return mirror().isLocalClass(); 931 } 932 933 @Override isMember()934 public boolean isMember() { 935 return mirror().isMemberClass(); 936 } 937 938 @Override getEnclosingType()939 public HotSpotResolvedObjectTypeImpl getEnclosingType() { 940 final Class<?> encl = mirror().getEnclosingClass(); 941 return encl == null ? null : fromObjectClass(encl); 942 } 943 944 @Override getDeclaredConstructors()945 public ResolvedJavaMethod[] getDeclaredConstructors() { 946 Constructor<?>[] constructors = mirror().getDeclaredConstructors(); 947 ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; 948 for (int i = 0; i < constructors.length; i++) { 949 result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]); 950 assert result[i].isConstructor(); 951 } 952 return result; 953 } 954 955 @Override getDeclaredMethods()956 public ResolvedJavaMethod[] getDeclaredMethods() { 957 Method[] methods = mirror().getDeclaredMethods(); 958 ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; 959 for (int i = 0; i < methods.length; i++) { 960 result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]); 961 assert !result[i].isConstructor(); 962 } 963 return result; 964 } 965 966 @Override getClassInitializer()967 public ResolvedJavaMethod getClassInitializer() { 968 if (!isArray()) { 969 return compilerToVM().getClassInitializer(this); 970 } 971 return null; 972 } 973 974 @Override toString()975 public String toString() { 976 return "HotSpotType<" + getName() + ", resolved>"; 977 } 978 979 @Override lookupType(UnresolvedJavaType unresolvedJavaType, boolean resolve)980 public ResolvedJavaType lookupType(UnresolvedJavaType unresolvedJavaType, boolean resolve) { 981 JavaType javaType = HotSpotJVMCIRuntime.runtime().lookupType(unresolvedJavaType.getName(), this, resolve); 982 if (javaType instanceof ResolvedJavaType) { 983 return (ResolvedJavaType) javaType; 984 } 985 return null; 986 } 987 988 @Override resolveField(UnresolvedJavaField unresolvedJavaField, ResolvedJavaType accessingClass)989 public ResolvedJavaField resolveField(UnresolvedJavaField unresolvedJavaField, ResolvedJavaType accessingClass) { 990 for (ResolvedJavaField field : getInstanceFields(false)) { 991 if (field.getName().equals(unresolvedJavaField.getName())) { 992 return field; 993 } 994 } 995 for (ResolvedJavaField field : getStaticFields()) { 996 if (field.getName().equals(unresolvedJavaField.getName())) { 997 return field; 998 } 999 } 1000 throw new InternalError(unresolvedJavaField.toString()); 1001 } 1002 1003 @Override isCloneableWithAllocation()1004 public boolean isCloneableWithAllocation() { 1005 return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0; 1006 } 1007 getMiscFlags()1008 private int getMiscFlags() { 1009 return UNSAFE.getInt(getMetaspaceKlass() + config().instanceKlassMiscFlagsOffset); 1010 } 1011 isAnonymous()1012 public boolean isAnonymous() { 1013 return (getMiscFlags() & config().instanceKlassMiscIsAnonymous) != 0; 1014 } 1015 1016 } 1017