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