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