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