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