1 /* 2 * Copyright (c) 2000, 2023, 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 */ 24 25 package sun.jvm.hotspot.oops; 26 27 import java.io.*; 28 import java.util.*; 29 import sun.jvm.hotspot.classfile.ClassLoaderData; 30 import sun.jvm.hotspot.code.CompressedReadStream; 31 import sun.jvm.hotspot.debugger.*; 32 import sun.jvm.hotspot.memory.*; 33 import sun.jvm.hotspot.runtime.*; 34 import sun.jvm.hotspot.types.*; 35 import sun.jvm.hotspot.utilities.*; 36 import sun.jvm.hotspot.utilities.Observable; 37 import sun.jvm.hotspot.utilities.Observer; 38 39 // An InstanceKlass is the VM level representation of a Java class. 40 41 public class InstanceKlass extends Klass { 42 static { 43 VM.registerVMInitializedObserver(new Observer() { 44 public void update(Observable o, Object data) { 45 initialize(VM.getVM().getTypeDataBase()); 46 } 47 }); 48 } 49 50 // internal field flags constants 51 static int FIELD_FLAG_IS_INITIALIZED; 52 static int FIELD_FLAG_IS_INJECTED; 53 static int FIELD_FLAG_IS_GENERIC; 54 static int FIELD_FLAG_IS_STABLE; 55 static int FIELD_FLAG_IS_CONTENDED; 56 57 // ClassState constants 58 private static int CLASS_STATE_ALLOCATED; 59 private static int CLASS_STATE_LOADED; 60 private static int CLASS_STATE_LINKED; 61 private static int CLASS_STATE_BEING_INITIALIZED; 62 private static int CLASS_STATE_FULLY_INITIALIZED; 63 private static int CLASS_STATE_INITIALIZATION_ERROR; 64 65 66 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { 67 Type type = db.lookupType("InstanceKlass"); 68 annotations = type.getAddressField("_annotations"); 69 arrayKlasses = new MetadataField(type.getAddressField("_array_klasses"), 0); 70 methods = type.getAddressField("_methods"); 71 defaultMethods = type.getAddressField("_default_methods"); 72 methodOrdering = type.getAddressField("_method_ordering"); 73 localInterfaces = type.getAddressField("_local_interfaces"); 74 transitiveInterfaces = type.getAddressField("_transitive_interfaces"); 75 fieldinfoStream = type.getAddressField("_fieldinfo_stream"); 76 constants = new MetadataField(type.getAddressField("_constants"), 0); 77 sourceDebugExtension = type.getAddressField("_source_debug_extension"); 78 innerClasses = type.getAddressField("_inner_classes"); 79 nestMembers = type.getAddressField("_nest_members"); 80 nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), 0); 81 staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), 0); 82 staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 0); 83 nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), 0); 84 initState = new CIntField(type.getCIntegerField("_init_state"), 0); 85 itableLen = new CIntField(type.getCIntegerField("_itable_len"), 0); 86 nestHostIndex = new CIntField(type.getCIntegerField("_nest_host_index"), 0); 87 hashOffset = new CIntField(type.getCIntegerField("_hash_offset"), 0); 88 if (VM.getVM().isJvmtiSupported()) { 89 breakpoints = type.getAddressField("_breakpoints"); 90 } 91 headerSize = type.getSize(); 92 93 // read internal field flags constants 94 FIELD_FLAG_IS_INITIALIZED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_initialized"); 95 FIELD_FLAG_IS_INJECTED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_injected"); 96 FIELD_FLAG_IS_GENERIC = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_generic"); 97 FIELD_FLAG_IS_STABLE = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_stable"); 98 FIELD_FLAG_IS_CONTENDED = db.lookupIntConstant("FieldInfo::FieldFlags::_ff_contended"); 99 100 101 // read ClassState constants 102 CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue(); 103 CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue(); 104 CLASS_STATE_LINKED = db.lookupIntConstant("InstanceKlass::linked").intValue(); 105 CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("InstanceKlass::being_initialized").intValue(); 106 CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("InstanceKlass::fully_initialized").intValue(); 107 CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("InstanceKlass::initialization_error").intValue(); 108 // We need a new fieldsCache each time we attach. 109 fieldsCache = new WeakHashMap<Address, Field[]>(); 110 } 111 112 public InstanceKlass(Address addr) { 113 super(addr); 114 115 // If the class hasn't yet reached the "loaded" init state, then don't go any further 116 // or we'll run into problems trying to look at fields that are not yet setup. 117 // Attempted lookups of this InstanceKlass via ClassLoaderDataGraph, ClassLoaderData, 118 // and Dictionary will all refuse to return it. The main purpose of allowing this 119 // InstanceKlass to initialize is so ClassLoaderData.getKlasses() will succeed, allowing 120 // ClassLoaderData.classesDo() to iterate over all Klasses (skipping those that are 121 // not yet fully loaded). 122 if (!isLoaded()) { 123 return; 124 } 125 126 if (getJavaFieldsCount() != getAllFieldsCount()) { 127 // Exercise the injected field logic 128 for (int i = getJavaFieldsCount(); i < getAllFieldsCount(); i++) { 129 getFieldName(i); 130 getFieldSignature(i); 131 } 132 } 133 } 134 135 private static AddressField annotations; 136 private static MetadataField arrayKlasses; 137 private static AddressField methods; 138 private static AddressField defaultMethods; 139 private static AddressField methodOrdering; 140 private static AddressField localInterfaces; 141 private static AddressField transitiveInterfaces; 142 private static AddressField fieldinfoStream; 143 private static MetadataField constants; 144 private static AddressField sourceDebugExtension; 145 private static AddressField innerClasses; 146 private static AddressField nestMembers; 147 private static CIntField nonstaticFieldSize; 148 private static CIntField staticFieldSize; 149 private static CIntField staticOopFieldCount; 150 private static CIntField nonstaticOopMapSize; 151 private static CIntField initState; 152 private static CIntField itableLen; 153 private static CIntField nestHostIndex; 154 private static CIntField hashOffset; 155 private static AddressField breakpoints; 156 157 // type safe enum for ClassState from instanceKlass.hpp 158 public static class ClassState { 159 public static final ClassState ALLOCATED = new ClassState("allocated"); 160 public static final ClassState LOADED = new ClassState("loaded"); 161 public static final ClassState LINKED = new ClassState("linked"); 162 public static final ClassState BEING_INITIALIZED = new ClassState("beingInitialized"); 163 public static final ClassState FULLY_INITIALIZED = new ClassState("fullyInitialized"); 164 public static final ClassState INITIALIZATION_ERROR = new ClassState("initializationError"); 165 166 private ClassState(String value) { 167 this.value = value; 168 } 169 170 public String toString() { 171 return value; 172 } 173 174 private String value; 175 } 176 177 public int getInitStateAsInt() { return (int) initState.getValue(this); } 178 public ClassState getInitState() { 179 int state = getInitStateAsInt(); 180 if (state == CLASS_STATE_ALLOCATED) { 181 return ClassState.ALLOCATED; 182 } else if (state == CLASS_STATE_LOADED) { 183 return ClassState.LOADED; 184 } else if (state == CLASS_STATE_LINKED) { 185 return ClassState.LINKED; 186 } else if (state == CLASS_STATE_BEING_INITIALIZED) { 187 return ClassState.BEING_INITIALIZED; 188 } else if (state == CLASS_STATE_FULLY_INITIALIZED) { 189 return ClassState.FULLY_INITIALIZED; 190 } else if (state == CLASS_STATE_INITIALIZATION_ERROR) { 191 return ClassState.INITIALIZATION_ERROR; 192 } else { 193 throw new RuntimeException("should not reach here"); 194 } 195 } 196 197 // initialization state quaries 198 public boolean isLoaded() { 199 return getInitStateAsInt() >= CLASS_STATE_LOADED; 200 } 201 202 public boolean isLinked() { 203 return getInitStateAsInt() >= CLASS_STATE_LINKED; 204 } 205 206 public boolean isInitialized() { 207 return getInitStateAsInt() == CLASS_STATE_FULLY_INITIALIZED; 208 } 209 210 public boolean isNotInitialized() { 211 return getInitStateAsInt() < CLASS_STATE_BEING_INITIALIZED; 212 } 213 214 public boolean isBeingInitialized() { 215 return getInitStateAsInt() == CLASS_STATE_BEING_INITIALIZED; 216 } 217 218 public boolean isInErrorState() { 219 return getInitStateAsInt() == CLASS_STATE_INITIALIZATION_ERROR; 220 } 221 222 public int getClassStatus() { 223 int result = 0; 224 if (isLinked()) { 225 result |= JVMDIClassStatus.VERIFIED | JVMDIClassStatus.PREPARED; 226 } 227 228 if (isInitialized()) { 229 if (Assert.ASSERTS_ENABLED) { 230 Assert.that(isLinked(), "Class status is not consistent"); 231 } 232 result |= JVMDIClassStatus.INITIALIZED; 233 } 234 235 if (isInErrorState()) { 236 result |= JVMDIClassStatus.ERROR; 237 } 238 return result; 239 } 240 241 // Byteside of the header 242 private static long headerSize; 243 244 public long getObjectSize(Oop object) { 245 long baseSize = getSizeHelper() * VM.getVM().getAddressSize(); 246 if (VM.getVM().isCompactObjectHeadersEnabled()) { 247 Mark mark = object.getMark(); 248 if (mark.isExpanded() && (getHashOffset() + 4 /* size of hash field */) > baseSize) { 249 // Needs extra word for identity hash-code. 250 return baseSize + VM.getVM().getBytesPerWord(); 251 } 252 } 253 return baseSize; 254 } 255 256 public long getSize() { // in number of bytes 257 long wordLength = VM.getVM().getBytesPerWord(); 258 long size = getHeaderSize() + 259 (getVtableLen() + 260 getItableLen() + 261 getNonstaticOopMapSize()) * wordLength; 262 if (isInterface()) { 263 size += wordLength; 264 } 265 return alignSize(size); 266 } 267 268 public static long getHeaderSize() { return headerSize; } 269 270 // Each InstanceKlass mirror instance will cache the Field[] array after it is decoded, 271 // but since there can be multiple InstanceKlass mirror instances per hotspot InstanceKlass, 272 // we also have a global cache that uses the Address of the hotspot InstanceKlass as the key. 273 private Field[] fields; 274 private static Map<Address, Field[]> fieldsCache; 275 276 Field getField(int index) { 277 synchronized (this) { 278 fields = fieldsCache.get(this.getAddress()); 279 if (fields == null) { 280 fields = Field.getFields(this); 281 fieldsCache.put(this.getAddress(), fields); 282 } else { 283 } 284 } 285 return fields[index]; 286 } 287 288 public short getFieldAccessFlags(int index) { 289 return (short)getField(index).getAccessFlags(); 290 } 291 292 public int getFieldNameIndex(int index) { 293 if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;"); 294 return getField(index).getNameIndex(); 295 } 296 297 public Symbol getFieldName(int index) { 298 // Cannot use getFieldNameIndex() because this method is also used for injected fields 299 return getField(index).getName(); 300 } 301 302 public Symbol getSymbolFromIndex(int cpIndex, boolean injected) { 303 if (injected) { 304 return vmSymbols.symbolAt(cpIndex); 305 } else { 306 return getConstants().getSymbolAt(cpIndex); 307 } 308 } 309 310 public int getFieldSignatureIndex(int index) { 311 if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;"); 312 return getField(index).getSignatureIndex(); 313 } 314 315 public Symbol getFieldSignature(int index) { 316 // Cannot use getFieldSignatureIndex() because this method is also use for injected fields 317 return getField(index).getSignature(); 318 } 319 320 public int getFieldGenericSignatureIndex(int index) { 321 return getField(index).getGenericSignatureIndex(); 322 } 323 324 public Symbol getFieldGenericSignature(int index) { 325 return getField(index).getGenericSignature(); 326 } 327 328 public int getFieldInitialValueIndex(int index) { 329 if (index >= getJavaFieldsCount()) throw new IndexOutOfBoundsException("not a Java field;"); 330 return getField(index).getInitialValueIndex(); 331 } 332 333 public int getFieldOffset(int index) { 334 return (int)getField(index).getOffset(); 335 } 336 337 // Accessors for declared fields 338 public Klass getArrayKlasses() { return (Klass) arrayKlasses.getValue(this); } 339 public MethodArray getMethods() { return new MethodArray(methods.getValue(getAddress())); } 340 341 public MethodArray getDefaultMethods() { 342 if (defaultMethods != null) { 343 Address addr = defaultMethods.getValue(getAddress()); 344 if ((addr != null) && (addr.getAddressAt(0) != null)) { 345 return new MethodArray(addr); 346 } else { 347 return null; 348 } 349 } else { 350 return null; 351 } 352 } 353 354 private int javaFieldsCount = -1; 355 private int allFieldsCount = -1; 356 357 private void initFieldCounts() { 358 CompressedReadStream crs = new CompressedReadStream(getFieldInfoStream().getDataStart()); 359 javaFieldsCount = crs.readInt(); // read num_java_fields 360 allFieldsCount = javaFieldsCount + crs.readInt(); // read num_injected_fields; 361 } 362 363 public int getJavaFieldsCount() { 364 if (javaFieldsCount == -1) { 365 initFieldCounts(); 366 } 367 return javaFieldsCount; 368 } 369 370 public int getAllFieldsCount() { 371 if (allFieldsCount == -1) { 372 initFieldCounts(); 373 } 374 return allFieldsCount; 375 } 376 377 public KlassArray getLocalInterfaces() { return new KlassArray(localInterfaces.getValue(getAddress())); } 378 public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); } 379 public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } 380 public Symbol getSourceFileName() { return getConstants().getSourceFileName(); } 381 public String getSourceDebugExtension(){ return CStringUtilities.getString(sourceDebugExtension.getValue(getAddress())); } 382 public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } 383 public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); } 384 public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); } 385 public long getItableLen() { return itableLen.getValue(this); } 386 public short getNestHostIndex() { return (short) nestHostIndex.getValue(this); } 387 public long getHashOffset() { return hashOffset.getValue(this); } 388 public long majorVersion() { return getConstants().majorVersion(); } 389 public long minorVersion() { return getConstants().minorVersion(); } 390 public Symbol getGenericSignature() { return getConstants().getGenericSignature(); } 391 // "size helper" == instance size in words 392 public long getSizeHelper() { 393 int lh = getLayoutHelper(); 394 if (Assert.ASSERTS_ENABLED) { 395 Assert.that(lh > 0, "layout helper initialized for instance class"); 396 } 397 return lh / VM.getVM().getAddressSize(); 398 } 399 public Annotations getAnnotations() { 400 Address addr = annotations.getValue(getAddress()); 401 return VMObjectFactory.newObject(Annotations.class, addr); 402 } 403 404 // same as enum InnerClassAttributeOffset in VM code. 405 private static class InnerClassAttributeOffset { 406 // from JVM spec. "InnerClasses" attribute 407 public static int innerClassInnerClassInfoOffset; 408 public static int innerClassOuterClassInfoOffset; 409 public static int innerClassInnerNameOffset; 410 public static int innerClassAccessFlagsOffset; 411 public static int innerClassNextOffset; 412 static { 413 VM.registerVMInitializedObserver(new Observer() { 414 public void update(Observable o, Object data) { 415 initialize(VM.getVM().getTypeDataBase()); 416 } 417 }); 418 } 419 420 private static synchronized void initialize(TypeDataBase db) { 421 innerClassInnerClassInfoOffset = db.lookupIntConstant( 422 "InstanceKlass::inner_class_inner_class_info_offset").intValue(); 423 innerClassOuterClassInfoOffset = db.lookupIntConstant( 424 "InstanceKlass::inner_class_outer_class_info_offset").intValue(); 425 innerClassInnerNameOffset = db.lookupIntConstant( 426 "InstanceKlass::inner_class_inner_name_offset").intValue(); 427 innerClassAccessFlagsOffset = db.lookupIntConstant( 428 "InstanceKlass::inner_class_access_flags_offset").intValue(); 429 innerClassNextOffset = db.lookupIntConstant( 430 "InstanceKlass::inner_class_next_offset").intValue(); 431 } 432 } 433 434 private static class EnclosingMethodAttributeOffset { 435 public static int enclosingMethodAttributeSize; 436 static { 437 VM.registerVMInitializedObserver(new Observer() { 438 public void update(Observable o, Object data) { 439 initialize(VM.getVM().getTypeDataBase()); 440 } 441 }); 442 } 443 private static synchronized void initialize(TypeDataBase db) { 444 enclosingMethodAttributeSize = db.lookupIntConstant("InstanceKlass::enclosing_method_attribute_size").intValue(); 445 } 446 } 447 448 // refer to compute_modifier_flags in VM code. 449 public long computeModifierFlags() { 450 long access = getAccessFlags(); 451 // But check if it happens to be member class. 452 U2Array innerClassList = getInnerClasses(); 453 int length = (innerClassList == null)? 0 : innerClassList.length(); 454 if (length > 0) { 455 if (Assert.ASSERTS_ENABLED) { 456 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 || 457 length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize, 458 "just checking"); 459 } 460 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { 461 if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) { 462 break; 463 } 464 int ioff = innerClassList.at(i + 465 InnerClassAttributeOffset.innerClassInnerClassInfoOffset); 466 // 'ioff' can be zero. 467 // refer to JVM spec. section 4.7.5. 468 if (ioff != 0) { 469 // only look at classes that are already loaded 470 // since we are looking for the flags for our self. 471 Symbol name = getConstants().getKlassNameAt(ioff); 472 473 if (name.equals(getName())) { 474 // This is really a member class 475 access = innerClassList.at(i + 476 InnerClassAttributeOffset.innerClassAccessFlagsOffset); 477 break; 478 } 479 } 480 } // for inner classes 481 } 482 483 // Remember to strip ACC_SUPER bit 484 return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS; 485 } 486 487 488 // whether given Symbol is name of an inner/nested Klass of this Klass? 489 // anonymous and local classes are excluded. 490 public boolean isInnerClassName(Symbol sym) { 491 return isInInnerClasses(sym, false); 492 } 493 494 // whether given Symbol is name of an inner/nested Klass of this Klass? 495 // anonymous classes excluded, but local classes are included. 496 public boolean isInnerOrLocalClassName(Symbol sym) { 497 return isInInnerClasses(sym, true); 498 } 499 500 private boolean isInInnerClasses(Symbol sym, boolean includeLocals) { 501 U2Array innerClassList = getInnerClasses(); 502 int length = ( innerClassList == null)? 0 : innerClassList.length(); 503 if (length > 0) { 504 if (Assert.ASSERTS_ENABLED) { 505 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 || 506 length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize, 507 "just checking"); 508 } 509 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { 510 if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) { 511 break; 512 } 513 int ioff = innerClassList.at(i + 514 InnerClassAttributeOffset.innerClassInnerClassInfoOffset); 515 // 'ioff' can be zero. 516 // refer to JVM spec. section 4.7.5. 517 if (ioff != 0) { 518 Symbol innerName = getConstants().getKlassNameAt(ioff); 519 Symbol myname = getName(); 520 int ooff = innerClassList.at(i + 521 InnerClassAttributeOffset.innerClassOuterClassInfoOffset); 522 // for anonymous classes inner_name_index of InnerClasses 523 // attribute is zero. 524 int innerNameIndex = innerClassList.at(i + 525 InnerClassAttributeOffset.innerClassInnerNameOffset); 526 // if this is not a member (anonymous, local etc.), 'ooff' will be zero 527 // refer to JVM spec. section 4.7.5. 528 if (ooff == 0) { 529 if (includeLocals) { 530 // does it looks like my local class? 531 if (innerName.equals(sym) && 532 innerName.asString().startsWith(myname.asString())) { 533 // exclude anonymous classes. 534 return (innerNameIndex != 0); 535 } 536 } 537 } else { 538 Symbol outerName = getConstants().getKlassNameAt(ooff); 539 540 // include only if current class is outer class. 541 if (outerName.equals(myname) && innerName.equals(sym)) { 542 return true; 543 } 544 } 545 } 546 } // for inner classes 547 return false; 548 } else { 549 return false; 550 } 551 } 552 553 public boolean implementsInterface(Klass k) { 554 if (Assert.ASSERTS_ENABLED) { 555 Assert.that(k.isInterface(), "should not reach here"); 556 } 557 KlassArray interfaces = getTransitiveInterfaces(); 558 final int len = interfaces.length(); 559 for (int i = 0; i < len; i++) { 560 if (interfaces.getAt(i).equals(k)) return true; 561 } 562 return false; 563 } 564 565 boolean computeSubtypeOf(Klass k) { 566 if (k.isInterface()) { 567 return implementsInterface(k); 568 } else { 569 return super.computeSubtypeOf(k); 570 } 571 } 572 573 public void printValueOn(PrintStream tty) { 574 tty.print("InstanceKlass for " + getName().asString()); 575 } 576 577 public void iterateFields(MetadataVisitor visitor) { 578 super.iterateFields(visitor); 579 visitor.doMetadata(arrayKlasses, true); 580 // visitor.doOop(methods, true); 581 // visitor.doOop(localInterfaces, true); 582 // visitor.doOop(transitiveInterfaces, true); 583 visitor.doCInt(nonstaticFieldSize, true); 584 visitor.doCInt(staticFieldSize, true); 585 visitor.doCInt(staticOopFieldCount, true); 586 visitor.doCInt(nonstaticOopMapSize, true); 587 visitor.doCInt(initState, true); 588 visitor.doCInt(itableLen, true); 589 } 590 591 /* 592 * Visit the static fields of this InstanceKlass with the obj of 593 * the visitor set to the oop holding the fields, which is 594 * currently the java mirror. 595 */ 596 public void iterateStaticFields(OopVisitor visitor) { 597 visitor.setObj(getJavaMirror()); 598 visitor.prologue(); 599 iterateStaticFieldsInternal(visitor); 600 visitor.epilogue(); 601 602 } 603 604 void iterateStaticFieldsInternal(OopVisitor visitor) { 605 int length = getJavaFieldsCount(); 606 for (int index = 0; index < length; index++) { 607 short accessFlags = getFieldAccessFlags(index); 608 FieldType type = new FieldType(getFieldSignature(index)); 609 AccessFlags access = new AccessFlags(accessFlags); 610 if (access.isStatic()) { 611 visitField(visitor, type, index); 612 } 613 } 614 } 615 616 public Klass getJavaSuper() { 617 return getSuper(); 618 } 619 620 public static class StaticField { 621 public AccessFlags flags; 622 public Field field; 623 624 StaticField(Field field, AccessFlags flags) { 625 this.field = field; 626 this.flags = flags; 627 } 628 } 629 630 public Field[] getStaticFields() { 631 int length = getJavaFieldsCount(); 632 ArrayList<Field> result = new ArrayList<>(); 633 for (int index = 0; index < length; index++) { 634 Field f = newField(index); 635 if (f.isStatic()) { 636 result.add(f); 637 } 638 } 639 return result.toArray(new Field[result.size()]); 640 } 641 642 public void iterateNonStaticFields(OopVisitor visitor, Oop obj) { 643 if (getSuper() != null) { 644 ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj); 645 } 646 int length = getJavaFieldsCount(); 647 for (int index = 0; index < length; index++) { 648 short accessFlags = getFieldAccessFlags(index); 649 FieldType type = new FieldType(getFieldSignature(index)); 650 AccessFlags access = new AccessFlags(accessFlags); 651 if (!access.isStatic()) { 652 visitField(visitor, type, index); 653 } 654 } 655 } 656 657 /** Field access by name. */ 658 public Field findLocalField(String name, String sig) { 659 int length = getJavaFieldsCount(); 660 for (int i = 0; i < length; i++) { 661 Symbol f_name = getFieldName(i); 662 Symbol f_sig = getFieldSignature(i); 663 if (f_name.equals(name) && f_sig.equals(sig)) { 664 return newField(i); 665 } 666 } 667 668 return null; 669 } 670 671 /** Find field in direct superinterfaces. */ 672 public Field findInterfaceField(String name, String sig) { 673 KlassArray interfaces = getLocalInterfaces(); 674 int n = interfaces.length(); 675 for (int i = 0; i < n; i++) { 676 InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i); 677 if (Assert.ASSERTS_ENABLED) { 678 Assert.that(intf1.isInterface(), "just checking type"); 679 } 680 // search for field in current interface 681 Field f = intf1.findLocalField(name, sig); 682 if (f != null) { 683 if (Assert.ASSERTS_ENABLED) { 684 Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static"); 685 } 686 return f; 687 } 688 // search for field in direct superinterfaces 689 f = intf1.findInterfaceField(name, sig); 690 if (f != null) return f; 691 } 692 // otherwise field lookup fails 693 return null; 694 } 695 696 /** Find field according to JVM spec 5.4.3.2, returns the klass in 697 which the field is defined. */ 698 public Field findField(String name, String sig) { 699 // search order according to newest JVM spec (5.4.3.2, p.167). 700 // 1) search for field in current klass 701 Field f = findLocalField(name, sig); 702 if (f != null) return f; 703 704 // 2) search for field recursively in direct superinterfaces 705 f = findInterfaceField(name, sig); 706 if (f != null) return f; 707 708 // 3) apply field lookup recursively if superclass exists 709 InstanceKlass supr = (InstanceKlass) getSuper(); 710 if (supr != null) return supr.findField(name, sig); 711 712 // 4) otherwise field lookup fails 713 return null; 714 } 715 716 /** Find field according to JVM spec 5.4.3.2, returns the klass in 717 which the field is defined (retained only for backward 718 compatibility with jdbx) */ 719 public Field findFieldDbg(String name, String sig) { 720 return findField(name, sig); 721 } 722 723 /** Get field by its index in the fields array. Only designed for 724 use in a debugging system. */ 725 public Field getFieldByIndex(int fieldIndex) { 726 return newField(fieldIndex); 727 } 728 729 730 /** Return a List of SA Fields for the fields declared in this class. 731 Inherited fields are not included. 732 Return an empty list if there are no fields declared in this class. 733 Only designed for use in a debugging system. */ 734 public List<Field> getImmediateFields() { 735 // A list of Fields for each field declared in this class/interface, 736 // not including inherited fields. 737 int length = getJavaFieldsCount(); 738 List<Field> immediateFields = new ArrayList<>(length); 739 for (int index = 0; index < length; index++) { 740 immediateFields.add(getFieldByIndex(index)); 741 } 742 743 return immediateFields; 744 } 745 746 /** Return a List of SA Fields for all the java fields in this class, 747 including all inherited fields. This includes hidden 748 fields. Thus the returned list can contain fields with 749 the same name. 750 Return an empty list if there are no fields. 751 Only designed for use in a debugging system. */ 752 public List<Field> getAllFields() { 753 // Contains a Field for each field in this class, including immediate 754 // fields and inherited fields. 755 List<Field> allFields = getImmediateFields(); 756 757 // transitiveInterfaces contains all interfaces implemented 758 // by this class and its superclass chain with no duplicates. 759 760 KlassArray interfaces = getTransitiveInterfaces(); 761 int n = interfaces.length(); 762 for (int i = 0; i < n; i++) { 763 InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i); 764 if (Assert.ASSERTS_ENABLED) { 765 Assert.that(intf1.isInterface(), "just checking type"); 766 } 767 allFields.addAll(intf1.getImmediateFields()); 768 } 769 770 // Get all fields in the superclass, recursively. But, don't 771 // include fields in interfaces implemented by superclasses; 772 // we already have all those. 773 if (!isInterface()) { 774 InstanceKlass supr; 775 if ( (supr = (InstanceKlass) getSuper()) != null) { 776 allFields.addAll(supr.getImmediateFields()); 777 } 778 } 779 780 return allFields; 781 } 782 783 784 /** Return a List of SA Methods declared directly in this class/interface. 785 Return an empty list if there are none, or if this isn't a class/ 786 interface. 787 */ 788 public List<Method> getImmediateMethods() { 789 // Contains a Method for each method declared in this class/interface 790 // not including inherited methods. 791 792 MethodArray methods = getMethods(); 793 int length = methods.length(); 794 Method[] tmp = new Method[length]; 795 796 IntArray methodOrdering = getMethodOrdering(); 797 if (methodOrdering.length() != length) { 798 // no ordering info present 799 for (int index = 0; index < length; index++) { 800 tmp[index] = methods.at(index); 801 } 802 } else { 803 for (int index = 0; index < length; index++) { 804 int originalIndex = methodOrdering.at(index); 805 tmp[originalIndex] = methods.at(index); 806 } 807 } 808 809 return Arrays.asList(tmp); 810 } 811 812 /** Return a List containing an SA InstanceKlass for each 813 interface named in this class's 'implements' clause. 814 */ 815 public List<Klass> getDirectImplementedInterfaces() { 816 // Contains an InstanceKlass for each interface in this classes 817 // 'implements' clause. 818 819 KlassArray interfaces = getLocalInterfaces(); 820 int length = interfaces.length(); 821 List<Klass> directImplementedInterfaces = new ArrayList<>(length); 822 823 for (int index = 0; index < length; index ++) { 824 directImplementedInterfaces.add(interfaces.getAt(index)); 825 } 826 827 return directImplementedInterfaces; 828 } 829 830 public Klass arrayKlassImpl(boolean orNull, int n) { 831 // FIXME: in reflective system this would need to change to 832 // actually allocate 833 if (getArrayKlasses() == null) { return null; } 834 ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses(); 835 if (orNull) { 836 return oak.arrayKlassOrNull(n); 837 } 838 return oak.arrayKlass(n); 839 } 840 841 public Klass arrayKlassImpl(boolean orNull) { 842 return arrayKlassImpl(orNull, 1); 843 } 844 845 public String signature() { 846 return "L" + super.signature() + ";"; 847 } 848 849 /** Find method in vtable. */ 850 public Method findMethod(String name, String sig) { 851 return findMethod(getMethods(), name, sig); 852 } 853 854 /** Breakpoint support (see methods on Method* for details) */ 855 public BreakpointInfo getBreakpoints() { 856 if (!VM.getVM().isJvmtiSupported()) { 857 return null; 858 } 859 Address addr = getAddress().getAddressAt(breakpoints.getOffset()); 860 return VMObjectFactory.newObject(BreakpointInfo.class, addr); 861 } 862 863 public IntArray getMethodOrdering() { 864 Address addr = getAddress().getAddressAt(methodOrdering.getOffset()); 865 return VMObjectFactory.newObject(IntArray.class, addr); 866 } 867 868 public U1Array getFieldInfoStream() { 869 Address addr = getAddress().getAddressAt(fieldinfoStream.getOffset()); 870 return VMObjectFactory.newObject(U1Array.class, addr); 871 } 872 873 public U2Array getInnerClasses() { 874 Address addr = getAddress().getAddressAt(innerClasses.getOffset()); 875 return VMObjectFactory.newObject(U2Array.class, addr); 876 } 877 878 public U1Array getClassAnnotations() { 879 Annotations annotations = getAnnotations(); 880 if (annotations != null) { 881 return annotations.getClassAnnotations(); 882 } else { 883 return null; 884 } 885 } 886 887 public U1Array getClassTypeAnnotations() { 888 Annotations annotations = getAnnotations(); 889 if (annotations != null) { 890 return annotations.getClassTypeAnnotations(); 891 } else { 892 return null; 893 } 894 } 895 896 public U1Array getFieldAnnotations(int fieldIndex) { 897 Annotations annotations = getAnnotations(); 898 if (annotations != null) { 899 return annotations.getFieldAnnotations(fieldIndex); 900 } else { 901 return null; 902 } 903 } 904 905 public U1Array getFieldTypeAnnotations(int fieldIndex) { 906 Annotations annotations = getAnnotations(); 907 if (annotations != null) { 908 return annotations.getFieldTypeAnnotations(fieldIndex); 909 } else { 910 return null; 911 } 912 } 913 914 public U2Array getNestMembers() { 915 Address addr = getAddress().getAddressAt(nestMembers.getOffset()); 916 return VMObjectFactory.newObject(U2Array.class, addr); 917 } 918 919 //---------------------------------------------------------------------- 920 // Internals only below this point 921 // 922 923 private void visitField(OopVisitor visitor, FieldType type, int index) { 924 Field f = newField(index); 925 if (type.isOop()) { 926 visitor.doOop((OopField) f, false); 927 return; 928 } 929 if (type.isByte()) { 930 visitor.doByte((ByteField) f, false); 931 return; 932 } 933 if (type.isChar()) { 934 visitor.doChar((CharField) f, false); 935 return; 936 } 937 if (type.isDouble()) { 938 visitor.doDouble((DoubleField) f, false); 939 return; 940 } 941 if (type.isFloat()) { 942 visitor.doFloat((FloatField) f, false); 943 return; 944 } 945 if (type.isInt()) { 946 visitor.doInt((IntField) f, false); 947 return; 948 } 949 if (type.isLong()) { 950 visitor.doLong((LongField) f, false); 951 return; 952 } 953 if (type.isShort()) { 954 visitor.doShort((ShortField) f, false); 955 return; 956 } 957 if (type.isBoolean()) { 958 visitor.doBoolean((BooleanField) f, false); 959 return; 960 } 961 } 962 963 // Creates new field from index in fields TypeArray 964 private Field newField(int index) { 965 FieldType type = new FieldType(getFieldSignature(index)); 966 if (type.isOop()) { 967 if (VM.getVM().isCompressedOopsEnabled()) { 968 return new NarrowOopField(this, index); 969 } else { 970 return new OopField(this, index); 971 } 972 } 973 if (type.isByte()) { 974 return new ByteField(this, index); 975 } 976 if (type.isChar()) { 977 return new CharField(this, index); 978 } 979 if (type.isDouble()) { 980 return new DoubleField(this, index); 981 } 982 if (type.isFloat()) { 983 return new FloatField(this, index); 984 } 985 if (type.isInt()) { 986 return new IntField(this, index); 987 } 988 if (type.isLong()) { 989 return new LongField(this, index); 990 } 991 if (type.isShort()) { 992 return new ShortField(this, index); 993 } 994 if (type.isBoolean()) { 995 return new BooleanField(this, index); 996 } 997 throw new RuntimeException("Illegal field type at index " + index); 998 } 999 1000 private static Method findMethod(MethodArray methods, String name, String signature) { 1001 int index = linearSearch(methods, name, signature); 1002 if (index != -1) { 1003 return methods.at(index); 1004 } else { 1005 return null; 1006 } 1007 } 1008 1009 private static int linearSearch(MethodArray methods, String name, String signature) { 1010 int len = methods.length(); 1011 for (int index = 0; index < len; index++) { 1012 Method m = methods.at(index); 1013 if (m.getSignature().equals(signature) && m.getName().equals(name)) { 1014 return index; 1015 } 1016 } 1017 return -1; 1018 } 1019 1020 public void dumpReplayData(PrintStream out) { 1021 ConstantPool cp = getConstants(); 1022 1023 // Try to record related loaded classes 1024 Klass sub = getSubklassKlass(); 1025 while (sub != null) { 1026 if (sub instanceof InstanceKlass) { 1027 out.println("instanceKlass " + sub.getName().asString()); 1028 } 1029 sub = sub.getNextSiblingKlass(); 1030 } 1031 1032 final int length = cp.getLength(); 1033 out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length); 1034 for (int index = 1; index < length; index++) { 1035 out.print(" " + cp.getTags().at(index)); 1036 } 1037 out.println(); 1038 if (isInitialized()) { 1039 Field[] staticFields = getStaticFields(); 1040 for (int i = 0; i < staticFields.length; i++) { 1041 Field f = staticFields[i]; 1042 Oop mirror = getJavaMirror(); 1043 if (f.isFinal() && !f.hasInitialValue()) { 1044 out.print("staticfield " + getName().asString() + " " + 1045 OopUtilities.escapeString(f.getID().getName()) + " " + 1046 f.getFieldType().getSignature().asString() + " "); 1047 if (f instanceof ByteField) { 1048 ByteField bf = (ByteField)f; 1049 out.println(bf.getValue(mirror)); 1050 } else if (f instanceof BooleanField) { 1051 BooleanField bf = (BooleanField)f; 1052 out.println(bf.getValue(mirror) ? 1 : 0); 1053 } else if (f instanceof ShortField) { 1054 ShortField bf = (ShortField)f; 1055 out.println(bf.getValue(mirror)); 1056 } else if (f instanceof CharField) { 1057 CharField bf = (CharField)f; 1058 out.println(bf.getValue(mirror) & 0xffff); 1059 } else if (f instanceof IntField) { 1060 IntField bf = (IntField)f; 1061 out.println(bf.getValue(mirror)); 1062 } else if (f instanceof LongField) { 1063 LongField bf = (LongField)f; 1064 out.println(bf.getValue(mirror)); 1065 } else if (f instanceof FloatField) { 1066 FloatField bf = (FloatField)f; 1067 out.println(Float.floatToRawIntBits(bf.getValue(mirror))); 1068 } else if (f instanceof DoubleField) { 1069 DoubleField bf = (DoubleField)f; 1070 out.println(Double.doubleToRawLongBits(bf.getValue(mirror))); 1071 } else if (f instanceof OopField) { 1072 OopField bf = (OopField)f; 1073 1074 Oop value = bf.getValue(mirror); 1075 if (value == null) { 1076 out.println("null"); 1077 } else if (value.isInstance()) { 1078 Instance inst = (Instance)value; 1079 if (inst.isA(SystemDictionary.getStringKlass())) { 1080 out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\""); 1081 } else { 1082 out.println(inst.getKlass().getName().asString()); 1083 } 1084 } else if (value.isObjArray()) { 1085 ObjArray oa = (ObjArray)value; 1086 Klass ek = (ObjArrayKlass)oa.getKlass(); 1087 out.println(oa.getLength() + " " + ek.getName().asString()); 1088 } else if (value.isTypeArray()) { 1089 TypeArray ta = (TypeArray)value; 1090 out.println(ta.getLength()); 1091 } else { 1092 out.println(value); 1093 } 1094 } 1095 } 1096 } 1097 } 1098 } 1099 }