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 @Override 482 public long getFingerprint() { 483 return compilerToVM().getFingerprint(getMetaspaceKlass()); 484 } 485 486 synchronized HotSpotResolvedJavaMethod createMethod(long metaspaceMethod) { 487 HotSpotResolvedJavaMethodImpl method = null; 488 if (methodCache == null) { 489 methodCache = new HashMap<>(8); 490 } else { 491 method = methodCache.get(metaspaceMethod); 492 } 493 if (method == null) { 494 method = new HotSpotResolvedJavaMethodImpl(this, metaspaceMethod); 495 methodCache.put(metaspaceMethod, method); 496 context.add(method); 497 } 498 return method; 499 } 500 501 public int getVtableLength() { 502 HotSpotVMConfig config = config(); 503 if (isInterface() || isArray()) { 504 /* Everything has the core vtable of java.lang.Object */ 505 return config.baseVtableLength(); 506 } 507 int result = UNSAFE.getInt(getMetaspaceKlass() + config.klassVtableLengthOffset) / (config.vtableEntrySize / config.heapWordSize); 508 assert result >= config.baseVtableLength() : UNSAFE.getInt(getMetaspaceKlass() + config.klassVtableLengthOffset) + " " + config.vtableEntrySize; 509 return result; 510 } 511 512 synchronized HotSpotResolvedJavaField createField(String fieldName, JavaType type, long offset, int rawFlags) { 513 HotSpotResolvedJavaField result = null; 514 515 final int flags = rawFlags & HotSpotModifiers.jvmFieldModifiers(); 516 517 final long id = offset + ((long) flags << 32); 518 519 // Must cache the fields, because the local load elimination only works if the 520 // objects from two field lookups are identical. 521 if (fieldCache == null) { 522 fieldCache = new HashMap<>(8); 523 } else { 524 result = fieldCache.get(id); 525 } 526 527 if (result == null) { 528 result = new HotSpotResolvedJavaFieldImpl(this, fieldName, type, offset, rawFlags); 529 fieldCache.put(id, result); 530 } else { 531 assert result.getName().equals(fieldName); 532 /* 533 * Comparing the types directly is too strict, because the type in the cache could be 534 * resolved while the incoming type is unresolved. The name comparison is sufficient 535 * because the type will always be resolved in the context of the holder. 536 */ 537 assert result.getType().getName().equals(type.getName()); 538 assert result.offset() == offset; 539 assert result.getModifiers() == flags; 540 } 541 542 return result; 543 } 544 545 @Override 546 public AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) { 547 HotSpotResolvedJavaMethod hmethod = (HotSpotResolvedJavaMethod) method; 548 HotSpotResolvedObjectType declaredHolder = hmethod.getDeclaringClass(); 549 /* 550 * Sometimes the receiver type in the graph hasn't stabilized to a subtype of declared 551 * holder, usually because of phis, so make sure that the type is related to the declared 552 * type before using it for lookup. Unlinked types should also be ignored because we can't 553 * resolve the proper method to invoke. Generally unlinked types in invokes should result in 554 * a deopt instead since they can't really be used if they aren't linked yet. 555 */ 556 if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) { 557 ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder); 558 if (result != null) { 559 return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result)); 560 } 561 return null; 562 } 563 /* 564 * The holder may be a subtype of the declaredHolder so make sure to resolve the method to 565 * the correct method for the subtype. 566 */ 567 HotSpotResolvedJavaMethod resolvedMethod = (HotSpotResolvedJavaMethod) resolveMethod(hmethod, this); 568 if (resolvedMethod == null) { 569 // The type isn't known to implement the method. 570 return null; 571 } 572 573 ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this); 574 if (result != null) { 575 return new AssumptionResult<>(result, new ConcreteMethod(method, this, result)); 576 } 577 return null; 578 } 579 580 /** 581 * This class represents the field information for one field contained in the fields array of an 582 * {@code InstanceKlass}. The implementation is similar to the native {@code FieldInfo} class. 583 */ 584 private class FieldInfo { 585 /** 586 * Native pointer into the array of Java shorts. 587 */ 588 private final long metaspaceData; 589 590 /** 591 * Creates a field info for the field in the fields array at index {@code index}. 592 * 593 * @param index index to the fields array 594 */ 595 FieldInfo(int index) { 596 HotSpotVMConfig config = config(); 597 // Get Klass::_fields 598 final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); 599 assert config.fieldInfoFieldSlots == 6 : "revisit the field parsing code"; 600 int offset = config.fieldInfoFieldSlots * Short.BYTES * index; 601 metaspaceData = metaspaceFields + config.arrayU2DataOffset + offset; 602 } 603 604 private int getAccessFlags() { 605 return readFieldSlot(config().fieldInfoAccessFlagsOffset); 606 } 607 608 private int getNameIndex() { 609 return readFieldSlot(config().fieldInfoNameIndexOffset); 610 } 611 612 private int getSignatureIndex() { 613 return readFieldSlot(config().fieldInfoSignatureIndexOffset); 614 } 615 616 public int getOffset() { 617 HotSpotVMConfig config = config(); 618 final int lowPacked = readFieldSlot(config.fieldInfoLowPackedOffset); 619 final int highPacked = readFieldSlot(config.fieldInfoHighPackedOffset); 620 final int offset = ((highPacked << Short.SIZE) | lowPacked) >> config.fieldInfoTagSize; 621 return offset; 622 } 623 624 /** 625 * Helper method to read an entry (slot) from the field array. Currently field info is laid 626 * on top an array of Java shorts. 627 */ 628 private int readFieldSlot(int index) { 629 int offset = Short.BYTES * index; 630 return UNSAFE.getChar(metaspaceData + offset); 631 } 632 633 /** 634 * Returns the name of this field as a {@link String}. If the field is an internal field the 635 * name index is pointing into the vmSymbols table. 636 */ 637 public String getName() { 638 final int nameIndex = getNameIndex(); 639 return isInternal() ? config().symbolAt(nameIndex) : getConstantPool().lookupUtf8(nameIndex); 640 } 641 642 /** 643 * Returns the signature of this field as {@link String}. If the field is an internal field 644 * the signature index is pointing into the vmSymbols table. 645 */ 646 public String getSignature() { 647 final int signatureIndex = getSignatureIndex(); 648 return isInternal() ? config().symbolAt(signatureIndex) : getConstantPool().lookupUtf8(signatureIndex); 649 } 650 651 public JavaType getType() { 652 String signature = getSignature(); 653 return runtime().lookupType(signature, HotSpotResolvedObjectTypeImpl.this, false); 654 } 655 656 private boolean isInternal() { 657 return (getAccessFlags() & config().jvmAccFieldInternal) != 0; 658 } 659 660 public boolean isStatic() { 661 return Modifier.isStatic(getAccessFlags()); 662 } 663 664 public boolean hasGenericSignature() { 665 return (getAccessFlags() & config().jvmAccFieldHasGenericSignature) != 0; 666 } 667 } 668 669 @SuppressFBWarnings(value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE", justification = "comparator is only used transiently") 670 private static class OffsetComparator implements java.util.Comparator<HotSpotResolvedJavaField> { 671 @Override 672 public int compare(HotSpotResolvedJavaField o1, HotSpotResolvedJavaField o2) { 673 return o1.offset() - o2.offset(); 674 } 675 } 676 677 @Override 678 public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { 679 if (instanceFields == null) { 680 if (isArray() || isInterface()) { 681 instanceFields = new HotSpotResolvedJavaField[0]; 682 } else { 683 final int fieldCount = getFieldCount(); 684 ArrayList<HotSpotResolvedJavaField> fieldsArray = new ArrayList<>(fieldCount); 685 686 for (int i = 0; i < fieldCount; i++) { 687 FieldInfo field = new FieldInfo(i); 688 689 // We are only interested in instance fields. 690 if (!field.isStatic()) { 691 HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); 692 fieldsArray.add(resolvedJavaField); 693 } 694 } 695 696 fieldsArray.sort(new OffsetComparator()); 697 698 HotSpotResolvedJavaField[] myFields = fieldsArray.toArray(new HotSpotResolvedJavaField[0]); 699 700 if (mirror() != Object.class) { 701 HotSpotResolvedJavaField[] superFields = (HotSpotResolvedJavaField[]) getSuperclass().getInstanceFields(true); 702 HotSpotResolvedJavaField[] fields = Arrays.copyOf(superFields, superFields.length + myFields.length); 703 System.arraycopy(myFields, 0, fields, superFields.length, myFields.length); 704 instanceFields = fields; 705 } else { 706 assert myFields.length == 0 : "java.lang.Object has fields!"; 707 instanceFields = myFields; 708 } 709 710 } 711 } 712 if (!includeSuperclasses) { 713 int myFieldsStart = 0; 714 while (myFieldsStart < instanceFields.length && !instanceFields[myFieldsStart].getDeclaringClass().equals(this)) { 715 myFieldsStart++; 716 } 717 if (myFieldsStart == 0) { 718 return instanceFields; 719 } 720 if (myFieldsStart == instanceFields.length) { 721 return new HotSpotResolvedJavaField[0]; 722 } 723 return Arrays.copyOfRange(instanceFields, myFieldsStart, instanceFields.length); 724 } 725 return instanceFields; 726 } 727 728 @Override 729 public ResolvedJavaField[] getStaticFields() { 730 if (isArray()) { 731 return new HotSpotResolvedJavaField[0]; 732 } else { 733 final int fieldCount = getFieldCount(); 734 ArrayList<HotSpotResolvedJavaField> fieldsArray = new ArrayList<>(fieldCount); 735 736 for (int i = 0; i < fieldCount; i++) { 737 FieldInfo field = new FieldInfo(i); 738 739 // We are only interested in static fields. 740 if (field.isStatic()) { 741 HotSpotResolvedJavaField resolvedJavaField = createField(field.getName(), field.getType(), field.getOffset(), field.getAccessFlags()); 742 fieldsArray.add(resolvedJavaField); 743 } 744 } 745 746 fieldsArray.sort(new OffsetComparator()); 747 return fieldsArray.toArray(new HotSpotResolvedJavaField[fieldsArray.size()]); 748 } 749 } 750 751 /** 752 * Returns the actual field count of this class's internal {@code InstanceKlass::_fields} array 753 * by walking the array and discounting the generic signature slots at the end of the array. 754 * 755 * <p> 756 * See {@code FieldStreamBase::init_generic_signature_start_slot} 757 */ 758 private int getFieldCount() { 759 HotSpotVMConfig config = config(); 760 final long metaspaceFields = UNSAFE.getAddress(getMetaspaceKlass() + config.instanceKlassFieldsOffset); 761 int metaspaceFieldsLength = UNSAFE.getInt(metaspaceFields + config.arrayU1LengthOffset); 762 int fieldCount = 0; 763 764 for (int i = 0, index = 0; i < metaspaceFieldsLength; i += config.fieldInfoFieldSlots, index++) { 765 FieldInfo field = new FieldInfo(index); 766 if (field.hasGenericSignature()) { 767 metaspaceFieldsLength--; 768 } 769 fieldCount++; 770 } 771 return fieldCount; 772 } 773 774 @Override 775 public Class<?> mirror() { 776 return javaClass; 777 } 778 779 @Override 780 public String getSourceFileName() { 781 HotSpotVMConfig config = config(); 782 final int sourceFileNameIndex = UNSAFE.getChar(getMetaspaceKlass() + config.instanceKlassSourceFileNameIndexOffset); 783 if (sourceFileNameIndex == 0) { 784 return null; 785 } 786 return getConstantPool().lookupUtf8(sourceFileNameIndex); 787 } 788 789 @Override 790 public Annotation[] getAnnotations() { 791 return mirror().getAnnotations(); 792 } 793 794 @Override 795 public Annotation[] getDeclaredAnnotations() { 796 return mirror().getDeclaredAnnotations(); 797 } 798 799 @Override 800 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { 801 return mirror().getAnnotation(annotationClass); 802 } 803 804 /** 805 * Performs a fast-path check that this type is resolved in the context of a given accessing 806 * class. A negative result does not mean this type is not resolved with respect to 807 * {@code accessingClass}. That can only be determined by 808 * {@linkplain HotSpotJVMCIRuntime#lookupType(String, HotSpotResolvedObjectType, boolean) 809 * re-resolving} the type. 810 */ 811 public boolean isDefinitelyResolvedWithRespectTo(ResolvedJavaType accessingClass) { 812 assert accessingClass != null; 813 ResolvedJavaType elementType = getElementalType(); 814 if (elementType.isPrimitive()) { 815 // Primitive type resolution is context free. 816 return true; 817 } 818 if (elementType.getName().startsWith("Ljava/")) { 819 // Classes in a java.* package can only be defined by the 820 // boot class loader. This is enforced by ClassLoader.preDefineClass() 821 assert mirror().getClassLoader() == null; 822 return true; 823 } 824 ClassLoader thisCl = mirror().getClassLoader(); 825 ClassLoader accessingClassCl = ((HotSpotResolvedObjectTypeImpl) accessingClass).mirror().getClassLoader(); 826 return thisCl == accessingClassCl; 827 } 828 829 @Override 830 public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { 831 if (isDefinitelyResolvedWithRespectTo(requireNonNull(accessingClass))) { 832 return this; 833 } 834 HotSpotResolvedObjectTypeImpl accessingType = (HotSpotResolvedObjectTypeImpl) accessingClass; 835 return (ResolvedJavaType) runtime().lookupType(getName(), accessingType, true); 836 } 837 838 /** 839 * Gets the metaspace Klass boxed in a {@link JavaConstant}. 840 */ 841 public Constant klass() { 842 return HotSpotMetaspaceConstantImpl.forMetaspaceObject(this, false); 843 } 844 845 public boolean isPrimaryType() { 846 return config().secondarySuperCacheOffset != superCheckOffset(); 847 } 848 849 public int superCheckOffset() { 850 HotSpotVMConfig config = config(); 851 return UNSAFE.getInt(getMetaspaceKlass() + config.superCheckOffsetOffset); 852 } 853 854 public long prototypeMarkWord() { 855 HotSpotVMConfig config = config(); 856 if (isArray()) { 857 return config.arrayPrototypeMarkWord(); 858 } else { 859 return UNSAFE.getAddress(getMetaspaceKlass() + config.prototypeMarkWordOffset); 860 } 861 } 862 863 @Override 864 public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedEntryKind) { 865 ResolvedJavaField[] declaredFields = getInstanceFields(true); 866 for (ResolvedJavaField field : declaredFields) { 867 HotSpotResolvedJavaField resolvedField = (HotSpotResolvedJavaField) field; 868 long resolvedFieldOffset = resolvedField.offset(); 869 // @formatter:off 870 if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && 871 expectedEntryKind.isPrimitive() && 872 !expectedEntryKind.equals(JavaKind.Void) && 873 resolvedField.getJavaKind().isPrimitive()) { 874 resolvedFieldOffset += 875 resolvedField.getJavaKind().getByteCount() - 876 Math.min(resolvedField.getJavaKind().getByteCount(), 4 + expectedEntryKind.getByteCount()); 877 } 878 if (resolvedFieldOffset == offset) { 879 return field; 880 } 881 // @formatter:on 882 } 883 return null; 884 } 885 886 @Override 887 public boolean isLocal() { 888 return mirror().isLocalClass(); 889 } 890 891 @Override 892 public boolean isMember() { 893 return mirror().isMemberClass(); 894 } 895 896 @Override 897 public HotSpotResolvedObjectTypeImpl getEnclosingType() { 898 final Class<?> encl = mirror().getEnclosingClass(); 899 return encl == null ? null : fromObjectClass(encl); 900 } 901 902 @Override 903 public ResolvedJavaMethod[] getDeclaredConstructors() { 904 Constructor<?>[] constructors = mirror().getDeclaredConstructors(); 905 ResolvedJavaMethod[] result = new ResolvedJavaMethod[constructors.length]; 906 for (int i = 0; i < constructors.length; i++) { 907 result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(constructors[i]); 908 assert result[i].isConstructor(); 909 } 910 return result; 911 } 912 913 @Override 914 public ResolvedJavaMethod[] getDeclaredMethods() { 915 Method[] methods = mirror().getDeclaredMethods(); 916 ResolvedJavaMethod[] result = new ResolvedJavaMethod[methods.length]; 917 for (int i = 0; i < methods.length; i++) { 918 result[i] = runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaMethod(methods[i]); 919 assert !result[i].isConstructor(); 920 } 921 return result; 922 } 923 924 public ResolvedJavaMethod getClassInitializer() { 925 return compilerToVM().getClassInitializer(this); 926 } 927 928 @Override 929 public String toString() { 930 return "HotSpotType<" + getName() + ", resolved>"; 931 } 932 933 @Override 934 public boolean isCloneableWithAllocation() { 935 return (getAccessFlags() & config().jvmAccIsCloneableFast) != 0; 936 } 937 }