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