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