1 /* 2 * Copyright (c) 2000, 2024, 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 // whether given Symbol is name of an inner/nested Klass of this Klass? 449 // anonymous and local classes are excluded. 450 public boolean isInnerClassName(Symbol sym) { 451 return isInInnerClasses(sym, false); 452 } 453 454 // whether given Symbol is name of an inner/nested Klass of this Klass? 455 // anonymous classes excluded, but local classes are included. 456 public boolean isInnerOrLocalClassName(Symbol sym) { 457 return isInInnerClasses(sym, true); 458 } 459 460 private boolean isInInnerClasses(Symbol sym, boolean includeLocals) { 461 U2Array innerClassList = getInnerClasses(); 462 int length = ( innerClassList == null)? 0 : innerClassList.length(); 463 if (length > 0) { 464 if (Assert.ASSERTS_ENABLED) { 465 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0 || 466 length % InnerClassAttributeOffset.innerClassNextOffset == EnclosingMethodAttributeOffset.enclosingMethodAttributeSize, 467 "just checking"); 468 } 469 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { 470 if (i == length - EnclosingMethodAttributeOffset.enclosingMethodAttributeSize) { 471 break; 472 } 473 int ioff = innerClassList.at(i + 474 InnerClassAttributeOffset.innerClassInnerClassInfoOffset); 475 // 'ioff' can be zero. 476 // refer to JVM spec. section 4.7.5. 477 if (ioff != 0) { 478 Symbol innerName = getConstants().getKlassNameAt(ioff); 479 Symbol myname = getName(); 480 int ooff = innerClassList.at(i + 481 InnerClassAttributeOffset.innerClassOuterClassInfoOffset); 482 // for anonymous classes inner_name_index of InnerClasses 483 // attribute is zero. 484 int innerNameIndex = innerClassList.at(i + 485 InnerClassAttributeOffset.innerClassInnerNameOffset); 486 // if this is not a member (anonymous, local etc.), 'ooff' will be zero 487 // refer to JVM spec. section 4.7.5. 488 if (ooff == 0) { 489 if (includeLocals) { 490 // does it looks like my local class? 491 if (innerName.equals(sym) && 492 innerName.asString().startsWith(myname.asString())) { 493 // exclude anonymous classes. 494 return (innerNameIndex != 0); 495 } 496 } 497 } else { 498 Symbol outerName = getConstants().getKlassNameAt(ooff); 499 500 // include only if current class is outer class. 501 if (outerName.equals(myname) && innerName.equals(sym)) { 502 return true; 503 } 504 } 505 } 506 } // for inner classes 507 return false; 508 } else { 509 return false; 510 } 511 } 512 513 public boolean implementsInterface(Klass k) { 514 if (Assert.ASSERTS_ENABLED) { 515 Assert.that(k.isInterface(), "should not reach here"); 516 } 517 KlassArray interfaces = getTransitiveInterfaces(); 518 final int len = interfaces.length(); 519 for (int i = 0; i < len; i++) { 520 if (interfaces.getAt(i).equals(k)) return true; 521 } 522 return false; 523 } 524 525 boolean computeSubtypeOf(Klass k) { 526 if (k.isInterface()) { 527 return implementsInterface(k); 528 } else { 529 return super.computeSubtypeOf(k); 530 } 531 } 532 533 public void printValueOn(PrintStream tty) { 534 tty.print("InstanceKlass for " + getName().asString()); 535 } 536 537 public void iterateFields(MetadataVisitor visitor) { 538 super.iterateFields(visitor); 539 visitor.doMetadata(arrayKlasses, true); 540 // visitor.doOop(methods, true); 541 // visitor.doOop(localInterfaces, true); 542 // visitor.doOop(transitiveInterfaces, true); 543 visitor.doCInt(nonstaticFieldSize, true); 544 visitor.doCInt(staticFieldSize, true); 545 visitor.doCInt(staticOopFieldCount, true); 546 visitor.doCInt(nonstaticOopMapSize, true); 547 visitor.doCInt(initState, true); 548 visitor.doCInt(itableLen, true); 549 } 550 551 /* 552 * Visit the static fields of this InstanceKlass with the obj of 553 * the visitor set to the oop holding the fields, which is 554 * currently the java mirror. 555 */ 556 public void iterateStaticFields(OopVisitor visitor) { 557 visitor.setObj(getJavaMirror()); 558 visitor.prologue(); 559 iterateStaticFieldsInternal(visitor); 560 visitor.epilogue(); 561 562 } 563 564 void iterateStaticFieldsInternal(OopVisitor visitor) { 565 int length = getJavaFieldsCount(); 566 for (int index = 0; index < length; index++) { 567 short accessFlags = getFieldAccessFlags(index); 568 FieldType type = new FieldType(getFieldSignature(index)); 569 AccessFlags access = new AccessFlags(accessFlags); 570 if (access.isStatic()) { 571 visitField(visitor, type, index); 572 } 573 } 574 } 575 576 public Klass getJavaSuper() { 577 return getSuper(); 578 } 579 580 public static class StaticField { 581 public AccessFlags flags; 582 public Field field; 583 584 StaticField(Field field, AccessFlags flags) { 585 this.field = field; 586 this.flags = flags; 587 } 588 } 589 590 public Field[] getStaticFields() { 591 int length = getJavaFieldsCount(); 592 ArrayList<Field> result = new ArrayList<>(); 593 for (int index = 0; index < length; index++) { 594 Field f = newField(index); 595 if (f.isStatic()) { 596 result.add(f); 597 } 598 } 599 return result.toArray(new Field[result.size()]); 600 } 601 602 public void iterateNonStaticFields(OopVisitor visitor, Oop obj) { 603 if (getSuper() != null) { 604 ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj); 605 } 606 int length = getJavaFieldsCount(); 607 for (int index = 0; index < length; index++) { 608 short accessFlags = getFieldAccessFlags(index); 609 FieldType type = new FieldType(getFieldSignature(index)); 610 AccessFlags access = new AccessFlags(accessFlags); 611 if (!access.isStatic()) { 612 visitField(visitor, type, index); 613 } 614 } 615 } 616 617 /** Field access by name. */ 618 public Field findLocalField(String name, String sig) { 619 int length = getJavaFieldsCount(); 620 for (int i = 0; i < length; i++) { 621 Symbol f_name = getFieldName(i); 622 Symbol f_sig = getFieldSignature(i); 623 if (f_name.equals(name) && f_sig.equals(sig)) { 624 return newField(i); 625 } 626 } 627 628 return null; 629 } 630 631 /** Find field in direct superinterfaces. */ 632 public Field findInterfaceField(String name, String sig) { 633 KlassArray interfaces = getLocalInterfaces(); 634 int n = interfaces.length(); 635 for (int i = 0; i < n; i++) { 636 InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i); 637 if (Assert.ASSERTS_ENABLED) { 638 Assert.that(intf1.isInterface(), "just checking type"); 639 } 640 // search for field in current interface 641 Field f = intf1.findLocalField(name, sig); 642 if (f != null) { 643 if (Assert.ASSERTS_ENABLED) { 644 Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static"); 645 } 646 return f; 647 } 648 // search for field in direct superinterfaces 649 f = intf1.findInterfaceField(name, sig); 650 if (f != null) return f; 651 } 652 // otherwise field lookup fails 653 return null; 654 } 655 656 /** Find field according to JVM spec 5.4.3.2, returns the klass in 657 which the field is defined. */ 658 public Field findField(String name, String sig) { 659 // search order according to newest JVM spec (5.4.3.2, p.167). 660 // 1) search for field in current klass 661 Field f = findLocalField(name, sig); 662 if (f != null) return f; 663 664 // 2) search for field recursively in direct superinterfaces 665 f = findInterfaceField(name, sig); 666 if (f != null) return f; 667 668 // 3) apply field lookup recursively if superclass exists 669 InstanceKlass supr = (InstanceKlass) getSuper(); 670 if (supr != null) return supr.findField(name, sig); 671 672 // 4) otherwise field lookup fails 673 return null; 674 } 675 676 /** Find field according to JVM spec 5.4.3.2, returns the klass in 677 which the field is defined (retained only for backward 678 compatibility with jdbx) */ 679 public Field findFieldDbg(String name, String sig) { 680 return findField(name, sig); 681 } 682 683 /** Get field by its index in the fields array. Only designed for 684 use in a debugging system. */ 685 public Field getFieldByIndex(int fieldIndex) { 686 return newField(fieldIndex); 687 } 688 689 690 /** Return a List of SA Fields for the fields declared in this class. 691 Inherited fields are not included. 692 Return an empty list if there are no fields declared in this class. 693 Only designed for use in a debugging system. */ 694 public List<Field> getImmediateFields() { 695 // A list of Fields for each field declared in this class/interface, 696 // not including inherited fields. 697 int length = getJavaFieldsCount(); 698 List<Field> immediateFields = new ArrayList<>(length); 699 for (int index = 0; index < length; index++) { 700 immediateFields.add(getFieldByIndex(index)); 701 } 702 703 return immediateFields; 704 } 705 706 /** Return a List of SA Fields for all the java fields in this class, 707 including all inherited fields. This includes hidden 708 fields. Thus the returned list can contain fields with 709 the same name. 710 Return an empty list if there are no fields. 711 Only designed for use in a debugging system. */ 712 public List<Field> getAllFields() { 713 // Contains a Field for each field in this class, including immediate 714 // fields and inherited fields. 715 List<Field> allFields = getImmediateFields(); 716 717 // transitiveInterfaces contains all interfaces implemented 718 // by this class and its superclass chain with no duplicates. 719 720 KlassArray interfaces = getTransitiveInterfaces(); 721 int n = interfaces.length(); 722 for (int i = 0; i < n; i++) { 723 InstanceKlass intf1 = (InstanceKlass) interfaces.getAt(i); 724 if (Assert.ASSERTS_ENABLED) { 725 Assert.that(intf1.isInterface(), "just checking type"); 726 } 727 allFields.addAll(intf1.getImmediateFields()); 728 } 729 730 // Get all fields in the superclass, recursively. But, don't 731 // include fields in interfaces implemented by superclasses; 732 // we already have all those. 733 if (!isInterface()) { 734 InstanceKlass supr; 735 if ( (supr = (InstanceKlass) getSuper()) != null) { 736 allFields.addAll(supr.getImmediateFields()); 737 } 738 } 739 740 return allFields; 741 } 742 743 744 /** Return a List of SA Methods declared directly in this class/interface. 745 Return an empty list if there are none, or if this isn't a class/ 746 interface. 747 */ 748 public List<Method> getImmediateMethods() { 749 // Contains a Method for each method declared in this class/interface 750 // not including inherited methods. 751 752 MethodArray methods = getMethods(); 753 int length = methods.length(); 754 Method[] tmp = new Method[length]; 755 756 IntArray methodOrdering = getMethodOrdering(); 757 if (methodOrdering.length() != length) { 758 // no ordering info present 759 for (int index = 0; index < length; index++) { 760 tmp[index] = methods.at(index); 761 } 762 } else { 763 for (int index = 0; index < length; index++) { 764 int originalIndex = methodOrdering.at(index); 765 tmp[originalIndex] = methods.at(index); 766 } 767 } 768 769 return Arrays.asList(tmp); 770 } 771 772 /** Return a List containing an SA InstanceKlass for each 773 interface named in this class's 'implements' clause. 774 */ 775 public List<Klass> getDirectImplementedInterfaces() { 776 // Contains an InstanceKlass for each interface in this classes 777 // 'implements' clause. 778 779 KlassArray interfaces = getLocalInterfaces(); 780 int length = interfaces.length(); 781 List<Klass> directImplementedInterfaces = new ArrayList<>(length); 782 783 for (int index = 0; index < length; index ++) { 784 directImplementedInterfaces.add(interfaces.getAt(index)); 785 } 786 787 return directImplementedInterfaces; 788 } 789 790 public Klass arrayKlassImpl(boolean orNull, int n) { 791 // FIXME: in reflective system this would need to change to 792 // actually allocate 793 if (getArrayKlasses() == null) { return null; } 794 ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses(); 795 if (orNull) { 796 return oak.arrayKlassOrNull(n); 797 } 798 return oak.arrayKlass(n); 799 } 800 801 public Klass arrayKlassImpl(boolean orNull) { 802 return arrayKlassImpl(orNull, 1); 803 } 804 805 public String signature() { 806 return "L" + super.signature() + ";"; 807 } 808 809 /** Find method in vtable. */ 810 public Method findMethod(String name, String sig) { 811 return findMethod(getMethods(), name, sig); 812 } 813 814 /** Breakpoint support (see methods on Method* for details) */ 815 public BreakpointInfo getBreakpoints() { 816 if (!VM.getVM().isJvmtiSupported()) { 817 return null; 818 } 819 Address addr = getAddress().getAddressAt(breakpoints.getOffset()); 820 return VMObjectFactory.newObject(BreakpointInfo.class, addr); 821 } 822 823 public IntArray getMethodOrdering() { 824 Address addr = getAddress().getAddressAt(methodOrdering.getOffset()); 825 return VMObjectFactory.newObject(IntArray.class, addr); 826 } 827 828 public U1Array getFieldInfoStream() { 829 Address addr = getAddress().getAddressAt(fieldinfoStream.getOffset()); 830 return VMObjectFactory.newObject(U1Array.class, addr); 831 } 832 833 public U2Array getInnerClasses() { 834 Address addr = getAddress().getAddressAt(innerClasses.getOffset()); 835 return VMObjectFactory.newObject(U2Array.class, addr); 836 } 837 838 public U1Array getClassAnnotations() { 839 Annotations annotations = getAnnotations(); 840 if (annotations != null) { 841 return annotations.getClassAnnotations(); 842 } else { 843 return null; 844 } 845 } 846 847 public U1Array getClassTypeAnnotations() { 848 Annotations annotations = getAnnotations(); 849 if (annotations != null) { 850 return annotations.getClassTypeAnnotations(); 851 } else { 852 return null; 853 } 854 } 855 856 public U1Array getFieldAnnotations(int fieldIndex) { 857 Annotations annotations = getAnnotations(); 858 if (annotations != null) { 859 return annotations.getFieldAnnotations(fieldIndex); 860 } else { 861 return null; 862 } 863 } 864 865 public U1Array getFieldTypeAnnotations(int fieldIndex) { 866 Annotations annotations = getAnnotations(); 867 if (annotations != null) { 868 return annotations.getFieldTypeAnnotations(fieldIndex); 869 } else { 870 return null; 871 } 872 } 873 874 public U2Array getNestMembers() { 875 Address addr = getAddress().getAddressAt(nestMembers.getOffset()); 876 return VMObjectFactory.newObject(U2Array.class, addr); 877 } 878 879 //---------------------------------------------------------------------- 880 // Internals only below this point 881 // 882 883 private void visitField(OopVisitor visitor, FieldType type, int index) { 884 Field f = newField(index); 885 if (type.isOop()) { 886 visitor.doOop((OopField) f, false); 887 return; 888 } 889 if (type.isByte()) { 890 visitor.doByte((ByteField) f, false); 891 return; 892 } 893 if (type.isChar()) { 894 visitor.doChar((CharField) f, false); 895 return; 896 } 897 if (type.isDouble()) { 898 visitor.doDouble((DoubleField) f, false); 899 return; 900 } 901 if (type.isFloat()) { 902 visitor.doFloat((FloatField) f, false); 903 return; 904 } 905 if (type.isInt()) { 906 visitor.doInt((IntField) f, false); 907 return; 908 } 909 if (type.isLong()) { 910 visitor.doLong((LongField) f, false); 911 return; 912 } 913 if (type.isShort()) { 914 visitor.doShort((ShortField) f, false); 915 return; 916 } 917 if (type.isBoolean()) { 918 visitor.doBoolean((BooleanField) f, false); 919 return; 920 } 921 } 922 923 // Creates new field from index in fields TypeArray 924 private Field newField(int index) { 925 FieldType type = new FieldType(getFieldSignature(index)); 926 if (type.isOop()) { 927 if (VM.getVM().isCompressedOopsEnabled()) { 928 return new NarrowOopField(this, index); 929 } else { 930 return new OopField(this, index); 931 } 932 } 933 if (type.isByte()) { 934 return new ByteField(this, index); 935 } 936 if (type.isChar()) { 937 return new CharField(this, index); 938 } 939 if (type.isDouble()) { 940 return new DoubleField(this, index); 941 } 942 if (type.isFloat()) { 943 return new FloatField(this, index); 944 } 945 if (type.isInt()) { 946 return new IntField(this, index); 947 } 948 if (type.isLong()) { 949 return new LongField(this, index); 950 } 951 if (type.isShort()) { 952 return new ShortField(this, index); 953 } 954 if (type.isBoolean()) { 955 return new BooleanField(this, index); 956 } 957 throw new RuntimeException("Illegal field type at index " + index); 958 } 959 960 private static Method findMethod(MethodArray methods, String name, String signature) { 961 int index = linearSearch(methods, name, signature); 962 if (index != -1) { 963 return methods.at(index); 964 } else { 965 return null; 966 } 967 } 968 969 private static int linearSearch(MethodArray methods, String name, String signature) { 970 int len = methods.length(); 971 for (int index = 0; index < len; index++) { 972 Method m = methods.at(index); 973 if (m.getSignature().equals(signature) && m.getName().equals(name)) { 974 return index; 975 } 976 } 977 return -1; 978 } 979 980 public void dumpReplayData(PrintStream out) { 981 ConstantPool cp = getConstants(); 982 983 // Try to record related loaded classes 984 Klass sub = getSubklassKlass(); 985 while (sub != null) { 986 if (sub instanceof InstanceKlass) { 987 out.println("instanceKlass " + sub.getName().asString()); 988 } 989 sub = sub.getNextSiblingKlass(); 990 } 991 992 final int length = cp.getLength(); 993 out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length); 994 for (int index = 1; index < length; index++) { 995 out.print(" " + cp.getTags().at(index)); 996 } 997 out.println(); 998 if (isInitialized()) { 999 Field[] staticFields = getStaticFields(); 1000 for (int i = 0; i < staticFields.length; i++) { 1001 Field f = staticFields[i]; 1002 Oop mirror = getJavaMirror(); 1003 if (f.isFinal() && !f.hasInitialValue()) { 1004 out.print("staticfield " + getName().asString() + " " + 1005 OopUtilities.escapeString(f.getID().getName()) + " " + 1006 f.getFieldType().getSignature().asString() + " "); 1007 if (f instanceof ByteField) { 1008 ByteField bf = (ByteField)f; 1009 out.println(bf.getValue(mirror)); 1010 } else if (f instanceof BooleanField) { 1011 BooleanField bf = (BooleanField)f; 1012 out.println(bf.getValue(mirror) ? 1 : 0); 1013 } else if (f instanceof ShortField) { 1014 ShortField bf = (ShortField)f; 1015 out.println(bf.getValue(mirror)); 1016 } else if (f instanceof CharField) { 1017 CharField bf = (CharField)f; 1018 out.println(bf.getValue(mirror) & 0xffff); 1019 } else if (f instanceof IntField) { 1020 IntField bf = (IntField)f; 1021 out.println(bf.getValue(mirror)); 1022 } else if (f instanceof LongField) { 1023 LongField bf = (LongField)f; 1024 out.println(bf.getValue(mirror)); 1025 } else if (f instanceof FloatField) { 1026 FloatField bf = (FloatField)f; 1027 out.println(Float.floatToRawIntBits(bf.getValue(mirror))); 1028 } else if (f instanceof DoubleField) { 1029 DoubleField bf = (DoubleField)f; 1030 out.println(Double.doubleToRawLongBits(bf.getValue(mirror))); 1031 } else if (f instanceof OopField) { 1032 OopField bf = (OopField)f; 1033 1034 Oop value = bf.getValue(mirror); 1035 if (value == null) { 1036 out.println("null"); 1037 } else if (value.isInstance()) { 1038 Instance inst = (Instance)value; 1039 if (inst.isA(SystemDictionary.getStringKlass())) { 1040 out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\""); 1041 } else { 1042 out.println(inst.getKlass().getName().asString()); 1043 } 1044 } else if (value.isObjArray()) { 1045 ObjArray oa = (ObjArray)value; 1046 Klass ek = (ObjArrayKlass)oa.getKlass(); 1047 out.println(oa.getLength() + " " + ek.getName().asString()); 1048 } else if (value.isTypeArray()) { 1049 TypeArray ta = (TypeArray)value; 1050 out.println(ta.getLength()); 1051 } else { 1052 out.println(value); 1053 } 1054 } 1055 } 1056 } 1057 } 1058 } 1059 }