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