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