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