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