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