1 /* 2 * Copyright 2000-2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.oops; 26 27 import java.io.*; 28 import java.util.*; 29 import sun.jvm.hotspot.debugger.*; 30 import sun.jvm.hotspot.memory.*; 31 import sun.jvm.hotspot.runtime.*; 32 import sun.jvm.hotspot.types.*; 33 import sun.jvm.hotspot.utilities.*; 34 35 // An InstanceKlass is the VM level representation of a Java class. 36 37 public class InstanceKlass extends Klass { 38 static { 39 VM.registerVMInitializedObserver(new Observer() { 40 public void update(Observable o, Object data) { 41 initialize(VM.getVM().getTypeDataBase()); 42 } 43 }); 44 } 45 46 // field offset constants 47 public static int ACCESS_FLAGS_OFFSET; 48 public static int NAME_INDEX_OFFSET; 49 public static int SIGNATURE_INDEX_OFFSET; 50 public static int INITVAL_INDEX_OFFSET; 51 public static int LOW_OFFSET; 52 public static int HIGH_OFFSET; 53 public static int GENERIC_SIGNATURE_INDEX_OFFSET; 54 public static int NEXT_OFFSET; 55 public static int IMPLEMENTORS_LIMIT; 56 57 // ClassState constants 58 private static int CLASS_STATE_UNPARSABLE_BY_GC; 59 private static int CLASS_STATE_ALLOCATED; 60 private static int CLASS_STATE_LOADED; 61 private static int CLASS_STATE_LINKED; 62 private static int CLASS_STATE_BEING_INITIALIZED; 63 private static int CLASS_STATE_FULLY_INITIALIZED; 64 private static int CLASS_STATE_INITIALIZATION_ERROR; 65 66 private static synchronized void initialize(TypeDataBase db) throws WrongTypeException { 67 Type type = db.lookupType("instanceKlass"); 68 arrayKlasses = new OopField(type.getOopField("_array_klasses"), Oop.getHeaderSize()); 69 methods = new OopField(type.getOopField("_methods"), Oop.getHeaderSize()); 70 methodOrdering = new OopField(type.getOopField("_method_ordering"), Oop.getHeaderSize()); 71 localInterfaces = new OopField(type.getOopField("_local_interfaces"), Oop.getHeaderSize()); 72 transitiveInterfaces = new OopField(type.getOopField("_transitive_interfaces"), Oop.getHeaderSize()); 73 nofImplementors = new CIntField(type.getCIntegerField("_nof_implementors"), Oop.getHeaderSize()); 74 IMPLEMENTORS_LIMIT = db.lookupIntConstant("instanceKlass::implementors_limit").intValue(); 75 implementors = new OopField[IMPLEMENTORS_LIMIT]; 76 for (int i = 0; i < IMPLEMENTORS_LIMIT; i++) { 77 long arrayOffset = Oop.getHeaderSize() + (i * db.getAddressSize()); 78 implementors[i] = new OopField(type.getOopField("_implementors[0]"), arrayOffset); 79 } 80 fields = new OopField(type.getOopField("_fields"), Oop.getHeaderSize()); 81 constants = new OopField(type.getOopField("_constants"), Oop.getHeaderSize()); 82 classLoader = new OopField(type.getOopField("_class_loader"), Oop.getHeaderSize()); 83 protectionDomain = new OopField(type.getOopField("_protection_domain"), Oop.getHeaderSize()); 84 signers = new OopField(type.getOopField("_signers"), Oop.getHeaderSize()); 85 sourceFileName = new OopField(type.getOopField("_source_file_name"), Oop.getHeaderSize()); 86 sourceDebugExtension = new OopField(type.getOopField("_source_debug_extension"), Oop.getHeaderSize()); 87 innerClasses = new OopField(type.getOopField("_inner_classes"), Oop.getHeaderSize()); 88 nonstaticFieldSize = new CIntField(type.getCIntegerField("_nonstatic_field_size"), Oop.getHeaderSize()); 89 staticFieldSize = new CIntField(type.getCIntegerField("_static_field_size"), Oop.getHeaderSize()); 90 staticOopFieldSize = new CIntField(type.getCIntegerField("_static_oop_field_size"), Oop.getHeaderSize()); 91 nonstaticOopMapSize = new CIntField(type.getCIntegerField("_nonstatic_oop_map_size"), Oop.getHeaderSize()); 92 isMarkedDependent = new CIntField(type.getCIntegerField("_is_marked_dependent"), Oop.getHeaderSize()); 93 initState = new CIntField(type.getCIntegerField("_init_state"), Oop.getHeaderSize()); 94 vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), Oop.getHeaderSize()); 95 itableLen = new CIntField(type.getCIntegerField("_itable_len"), Oop.getHeaderSize()); 96 breakpoints = type.getAddressField("_breakpoints"); 97 genericSignature = new OopField(type.getOopField("_generic_signature"), Oop.getHeaderSize()); 98 majorVersion = new CIntField(type.getCIntegerField("_major_version"), Oop.getHeaderSize()); 99 minorVersion = new CIntField(type.getCIntegerField("_minor_version"), Oop.getHeaderSize()); 100 headerSize = alignObjectOffset(Oop.getHeaderSize() + type.getSize()); 101 102 // read field offset constants 103 ACCESS_FLAGS_OFFSET = db.lookupIntConstant("instanceKlass::access_flags_offset").intValue(); 104 NAME_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::name_index_offset").intValue(); 105 SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::signature_index_offset").intValue(); 106 INITVAL_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::initval_index_offset").intValue(); 107 LOW_OFFSET = db.lookupIntConstant("instanceKlass::low_offset").intValue(); 108 HIGH_OFFSET = db.lookupIntConstant("instanceKlass::high_offset").intValue(); 109 GENERIC_SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("instanceKlass::generic_signature_offset").intValue(); 110 NEXT_OFFSET = db.lookupIntConstant("instanceKlass::next_offset").intValue(); 111 // read ClassState constants 112 CLASS_STATE_UNPARSABLE_BY_GC = db.lookupIntConstant("instanceKlass::unparsable_by_gc").intValue(); 113 CLASS_STATE_ALLOCATED = db.lookupIntConstant("instanceKlass::allocated").intValue(); 114 CLASS_STATE_LOADED = db.lookupIntConstant("instanceKlass::loaded").intValue(); 115 CLASS_STATE_LINKED = db.lookupIntConstant("instanceKlass::linked").intValue(); 116 CLASS_STATE_BEING_INITIALIZED = db.lookupIntConstant("instanceKlass::being_initialized").intValue(); 117 CLASS_STATE_FULLY_INITIALIZED = db.lookupIntConstant("instanceKlass::fully_initialized").intValue(); 118 CLASS_STATE_INITIALIZATION_ERROR = db.lookupIntConstant("instanceKlass::initialization_error").intValue(); 119 120 } 121 122 InstanceKlass(OopHandle handle, ObjectHeap heap) { 123 super(handle, heap); 124 } 125 126 private static OopField arrayKlasses; 127 private static OopField methods; 128 private static OopField methodOrdering; 129 private static OopField localInterfaces; 130 private static OopField transitiveInterfaces; 131 private static CIntField nofImplementors; 132 private static OopField[] implementors; 133 private static OopField fields; 134 private static OopField constants; 135 private static OopField classLoader; 136 private static OopField protectionDomain; 137 private static OopField signers; 138 private static OopField sourceFileName; 139 private static OopField sourceDebugExtension; 140 private static OopField innerClasses; 141 private static CIntField nonstaticFieldSize; 142 private static CIntField staticFieldSize; 143 private static CIntField staticOopFieldSize; 144 private static CIntField nonstaticOopMapSize; 145 private static CIntField isMarkedDependent; 146 private static CIntField initState; 147 private static CIntField vtableLen; 148 private static CIntField itableLen; 149 private static AddressField breakpoints; 150 private static OopField genericSignature; 151 private static CIntField majorVersion; 152 private static CIntField minorVersion; 153 154 // type safe enum for ClassState from instanceKlass.hpp 155 public static class ClassState { 156 public static final ClassState UNPARSABLE_BY_GC = new ClassState("unparsable_by_gc"); 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 private int getInitStateAsInt() { return (int) initState.getValue(this); } 176 public ClassState getInitState() { 177 int state = getInitStateAsInt(); 178 if (state == CLASS_STATE_UNPARSABLE_BY_GC) { 179 return ClassState.UNPARSABLE_BY_GC; 180 } else 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 static long getHeaderSize() { return headerSize; } 245 246 // Accessors for declared fields 247 public Klass getArrayKlasses() { return (Klass) arrayKlasses.getValue(this); } 248 public ObjArray getMethods() { return (ObjArray) methods.getValue(this); } 249 public TypeArray getMethodOrdering() { return (TypeArray) methodOrdering.getValue(this); } 250 public ObjArray getLocalInterfaces() { return (ObjArray) localInterfaces.getValue(this); } 251 public ObjArray getTransitiveInterfaces() { return (ObjArray) transitiveInterfaces.getValue(this); } 252 public long nofImplementors() { return nofImplementors.getValue(this); } 253 public Klass getImplementor() { return (Klass) implementors[0].getValue(this); } 254 public Klass getImplementor(int i) { return (Klass) implementors[i].getValue(this); } 255 public TypeArray getFields() { return (TypeArray) fields.getValue(this); } 256 public ConstantPool getConstants() { return (ConstantPool) constants.getValue(this); } 257 public Oop getClassLoader() { return classLoader.getValue(this); } 258 public Oop getProtectionDomain() { return protectionDomain.getValue(this); } 259 public ObjArray getSigners() { return (ObjArray) signers.getValue(this); } 260 public Symbol getSourceFileName() { return (Symbol) sourceFileName.getValue(this); } 261 public Symbol getSourceDebugExtension(){ return (Symbol) sourceDebugExtension.getValue(this); } 262 public TypeArray getInnerClasses() { return (TypeArray) innerClasses.getValue(this); } 263 public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } 264 public long getStaticFieldSize() { return staticFieldSize.getValue(this); } 265 public long getStaticOopFieldSize() { return staticOopFieldSize.getValue(this); } 266 public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); } 267 public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; } 268 public long getVtableLen() { return vtableLen.getValue(this); } 269 public long getItableLen() { return itableLen.getValue(this); } 270 public Symbol getGenericSignature() { return (Symbol) genericSignature.getValue(this); } 271 public long majorVersion() { return majorVersion.getValue(this); } 272 public long minorVersion() { return minorVersion.getValue(this); } 273 274 // "size helper" == instance size in words 275 public long getSizeHelper() { 276 int lh = getLayoutHelper(); 277 if (Assert.ASSERTS_ENABLED) { 278 Assert.that(lh > 0, "layout helper initialized for instance class"); 279 } 280 return lh / VM.getVM().getAddressSize(); 281 } 282 283 // same as enum InnerClassAttributeOffset in VM code. 284 public static interface InnerClassAttributeOffset { 285 // from JVM spec. "InnerClasses" attribute 286 public static final int innerClassInnerClassInfoOffset = 0; 287 public static final int innerClassOuterClassInfoOffset = 1; 288 public static final int innerClassInnerNameOffset = 2; 289 public static final int innerClassAccessFlagsOffset = 3; 290 public static final int innerClassNextOffset = 4; 291 }; 292 293 // refer to compute_modifier_flags in VM code. 294 public long computeModifierFlags() { 295 long access = getAccessFlags(); 296 // But check if it happens to be member class. 297 TypeArray innerClassList = getInnerClasses(); 298 int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength(); 299 if (length > 0) { 300 if (Assert.ASSERTS_ENABLED) { 301 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking"); 302 } 303 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { 304 int ioff = innerClassList.getShortAt(i + 305 InnerClassAttributeOffset.innerClassInnerClassInfoOffset); 306 // 'ioff' can be zero. 307 // refer to JVM spec. section 4.7.5. 308 if (ioff != 0) { 309 // only look at classes that are already loaded 310 // since we are looking for the flags for our self. 311 Oop classInfo = getConstants().getObjAt(ioff); 312 Symbol name = null; 313 if (classInfo instanceof Klass) { 314 name = ((Klass) classInfo).getName(); 315 } else if (classInfo instanceof Symbol) { 316 name = (Symbol) classInfo; 317 } else { 318 throw new RuntimeException("should not reach here"); 319 } 320 321 if (name.equals(getName())) { 322 // This is really a member class 323 access = innerClassList.getShortAt(i + 324 InnerClassAttributeOffset.innerClassAccessFlagsOffset); 325 break; 326 } 327 } 328 } // for inner classes 329 } 330 331 // Remember to strip ACC_SUPER bit 332 return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS; 333 } 334 335 336 // whether given Symbol is name of an inner/nested Klass of this Klass? 337 // anonymous and local classes are excluded. 338 public boolean isInnerClassName(Symbol sym) { 339 return isInInnerClasses(sym, false); 340 } 341 342 // whether given Symbol is name of an inner/nested Klass of this Klass? 343 // anonymous classes excluded, but local classes are included. 344 public boolean isInnerOrLocalClassName(Symbol sym) { 345 return isInInnerClasses(sym, true); 346 } 347 348 private boolean isInInnerClasses(Symbol sym, boolean includeLocals) { 349 TypeArray innerClassList = getInnerClasses(); 350 int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength(); 351 if (length > 0) { 352 if (Assert.ASSERTS_ENABLED) { 353 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking"); 354 } 355 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { 356 int ioff = innerClassList.getShortAt(i + 357 InnerClassAttributeOffset.innerClassInnerClassInfoOffset); 358 // 'ioff' can be zero. 359 // refer to JVM spec. section 4.7.5. 360 if (ioff != 0) { 361 Oop iclassInfo = getConstants().getObjAt(ioff); 362 Symbol innerName = null; 363 if (iclassInfo instanceof Klass) { 364 innerName = ((Klass) iclassInfo).getName(); 365 } else if (iclassInfo instanceof Symbol) { 366 innerName = (Symbol) iclassInfo; 367 } else { 368 throw new RuntimeException("should not reach here"); 369 } 370 371 Symbol myname = getName(); 372 int ooff = innerClassList.getShortAt(i + 373 InnerClassAttributeOffset.innerClassOuterClassInfoOffset); 374 // for anonymous classes inner_name_index of InnerClasses 375 // attribute is zero. 376 int innerNameIndex = innerClassList.getShortAt(i + 377 InnerClassAttributeOffset.innerClassInnerNameOffset); 378 // if this is not a member (anonymous, local etc.), 'ooff' will be zero 379 // refer to JVM spec. section 4.7.5. 380 if (ooff == 0) { 381 if (includeLocals) { 382 // does it looks like my local class? 383 if (innerName.equals(sym) && 384 innerName.asString().startsWith(myname.asString())) { 385 // exclude anonymous classes. 386 return (innerNameIndex != 0); 387 } 388 } 389 } else { 390 Oop oclassInfo = getConstants().getObjAt(ooff); 391 Symbol outerName = null; 392 if (oclassInfo instanceof Klass) { 393 outerName = ((Klass) oclassInfo).getName(); 394 } else if (oclassInfo instanceof Symbol) { 395 outerName = (Symbol) oclassInfo; 396 } else { 397 throw new RuntimeException("should not reach here"); 398 } 399 400 // include only if current class is outer class. 401 if (outerName.equals(myname) && innerName.equals(sym)) { 402 return true; 403 } 404 } 405 } 406 } // for inner classes 407 return false; 408 } else { 409 return false; 410 } 411 } 412 413 public boolean implementsInterface(Klass k) { 414 if (Assert.ASSERTS_ENABLED) { 415 Assert.that(k.isInterface(), "should not reach here"); 416 } 417 ObjArray interfaces = getTransitiveInterfaces(); 418 final int len = (int) interfaces.getLength(); 419 for (int i = 0; i < len; i++) { 420 if (interfaces.getObjAt(i).equals(k)) return true; 421 } 422 return false; 423 } 424 425 boolean computeSubtypeOf(Klass k) { 426 if (k.isInterface()) { 427 return implementsInterface(k); 428 } else { 429 return super.computeSubtypeOf(k); 430 } 431 } 432 433 public void printValueOn(PrintStream tty) { 434 tty.print("InstanceKlass for " + getName().asString()); 435 } 436 437 public void iterateFields(OopVisitor visitor, boolean doVMFields) { 438 super.iterateFields(visitor, doVMFields); 439 if (doVMFields) { 440 visitor.doOop(arrayKlasses, true); 441 visitor.doOop(methods, true); 442 visitor.doOop(methodOrdering, true); 443 visitor.doOop(localInterfaces, true); 444 visitor.doOop(transitiveInterfaces, true); 445 visitor.doCInt(nofImplementors, true); 446 for (int i = 0; i < IMPLEMENTORS_LIMIT; i++) 447 visitor.doOop(implementors[i], true); 448 visitor.doOop(fields, true); 449 visitor.doOop(constants, true); 450 visitor.doOop(classLoader, true); 451 visitor.doOop(protectionDomain, true); 452 visitor.doOop(signers, true); 453 visitor.doOop(sourceFileName, true); 454 visitor.doOop(innerClasses, true); 455 visitor.doCInt(nonstaticFieldSize, true); 456 visitor.doCInt(staticFieldSize, true); 457 visitor.doCInt(staticOopFieldSize, true); 458 visitor.doCInt(nonstaticOopMapSize, true); 459 visitor.doCInt(isMarkedDependent, true); 460 visitor.doCInt(initState, true); 461 visitor.doCInt(vtableLen, true); 462 visitor.doCInt(itableLen, true); 463 } 464 465 TypeArray fields = getFields(); 466 int length = (int) fields.getLength(); 467 for (int index = 0; index < length; index += NEXT_OFFSET) { 468 short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET); 469 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); 470 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex)); 471 AccessFlags access = new AccessFlags(accessFlags); 472 if (access.isStatic()) { 473 visitField(visitor, type, index); 474 } 475 } 476 } 477 478 public Klass getJavaSuper() { 479 return getSuper(); 480 } 481 482 public void iterateNonStaticFields(OopVisitor visitor) { 483 if (getSuper() != null) { 484 ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor); 485 } 486 TypeArray fields = getFields(); 487 488 int length = (int) fields.getLength(); 489 for (int index = 0; index < length; index += NEXT_OFFSET) { 490 short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET); 491 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); 492 493 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex)); 494 AccessFlags access = new AccessFlags(accessFlags); 495 if (!access.isStatic()) { 496 visitField(visitor, type, index); 497 } 498 } 499 } 500 501 /** Field access by name. */ 502 public Field findLocalField(Symbol name, Symbol sig) { 503 TypeArray fields = getFields(); 504 int n = (int) fields.getLength(); 505 ConstantPool cp = getConstants(); 506 for (int i = 0; i < n; i += NEXT_OFFSET) { 507 int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET); 508 int sigIndex = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET); 509 Symbol f_name = cp.getSymbolAt(nameIndex); 510 Symbol f_sig = cp.getSymbolAt(sigIndex); 511 if (name.equals(f_name) && sig.equals(f_sig)) { 512 return newField(i); 513 } 514 } 515 516 return null; 517 } 518 519 /** Find field in direct superinterfaces. */ 520 public Field findInterfaceField(Symbol name, Symbol sig) { 521 ObjArray interfaces = getLocalInterfaces(); 522 int n = (int) interfaces.getLength(); 523 for (int i = 0; i < n; i++) { 524 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i); 525 if (Assert.ASSERTS_ENABLED) { 526 Assert.that(intf1.isInterface(), "just checking type"); 527 } 528 // search for field in current interface 529 Field f = intf1.findLocalField(name, sig); 530 if (f != null) { 531 if (Assert.ASSERTS_ENABLED) { 532 Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static"); 533 } 534 return f; 535 } 536 // search for field in direct superinterfaces 537 f = intf1.findInterfaceField(name, sig); 538 if (f != null) return f; 539 } 540 // otherwise field lookup fails 541 return null; 542 } 543 544 /** Find field according to JVM spec 5.4.3.2, returns the klass in 545 which the field is defined. */ 546 public Field findField(Symbol name, Symbol sig) { 547 // search order according to newest JVM spec (5.4.3.2, p.167). 548 // 1) search for field in current klass 549 Field f = findLocalField(name, sig); 550 if (f != null) return f; 551 552 // 2) search for field recursively in direct superinterfaces 553 f = findInterfaceField(name, sig); 554 if (f != null) return f; 555 556 // 3) apply field lookup recursively if superclass exists 557 InstanceKlass supr = (InstanceKlass) getSuper(); 558 if (supr != null) return supr.findField(name, sig); 559 560 // 4) otherwise field lookup fails 561 return null; 562 } 563 564 /** Find field according to JVM spec 5.4.3.2, returns the klass in 565 which the field is defined (convenience routine) */ 566 public Field findField(String name, String sig) { 567 SymbolTable symbols = VM.getVM().getSymbolTable(); 568 Symbol nameSym = symbols.probe(name); 569 Symbol sigSym = symbols.probe(sig); 570 if (nameSym == null || sigSym == null) { 571 return null; 572 } 573 return findField(nameSym, sigSym); 574 } 575 576 /** Find field according to JVM spec 5.4.3.2, returns the klass in 577 which the field is defined (retained only for backward 578 compatibility with jdbx) */ 579 public Field findFieldDbg(String name, String sig) { 580 return findField(name, sig); 581 } 582 583 /** Get field by its index in the fields array. Only designed for 584 use in a debugging system. */ 585 public Field getFieldByIndex(int fieldArrayIndex) { 586 return newField(fieldArrayIndex); 587 } 588 589 590 /** Return a List of SA Fields for the fields declared in this class. 591 Inherited fields are not included. 592 Return an empty list if there are no fields declared in this class. 593 Only designed for use in a debugging system. */ 594 public List getImmediateFields() { 595 // A list of Fields for each field declared in this class/interface, 596 // not including inherited fields. 597 TypeArray fields = getFields(); 598 599 int length = (int) fields.getLength(); 600 List immediateFields = new ArrayList(length / NEXT_OFFSET); 601 for (int index = 0; index < length; index += NEXT_OFFSET) { 602 immediateFields.add(getFieldByIndex(index)); 603 } 604 605 return immediateFields; 606 } 607 608 /** Return a List of SA Fields for all the java fields in this class, 609 including all inherited fields. This includes hidden 610 fields. Thus the returned list can contain fields with 611 the same name. 612 Return an empty list if there are no fields. 613 Only designed for use in a debugging system. */ 614 public List getAllFields() { 615 // Contains a Field for each field in this class, including immediate 616 // fields and inherited fields. 617 List allFields = getImmediateFields(); 618 619 // transitiveInterfaces contains all interfaces implemented 620 // by this class and its superclass chain with no duplicates. 621 622 ObjArray interfaces = getTransitiveInterfaces(); 623 int n = (int) interfaces.getLength(); 624 for (int i = 0; i < n; i++) { 625 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i); 626 if (Assert.ASSERTS_ENABLED) { 627 Assert.that(intf1.isInterface(), "just checking type"); 628 } 629 allFields.addAll(intf1.getImmediateFields()); 630 } 631 632 // Get all fields in the superclass, recursively. But, don't 633 // include fields in interfaces implemented by superclasses; 634 // we already have all those. 635 if (!isInterface()) { 636 InstanceKlass supr; 637 if ( (supr = (InstanceKlass) getSuper()) != null) { 638 allFields.addAll(supr.getImmediateFields()); 639 } 640 } 641 642 return allFields; 643 } 644 645 646 /** Return a List of SA Methods declared directly in this class/interface. 647 Return an empty list if there are none, or if this isn't a class/ 648 interface. 649 */ 650 public List getImmediateMethods() { 651 // Contains a Method for each method declared in this class/interface 652 // not including inherited methods. 653 654 ObjArray methods = getMethods(); 655 int length = (int)methods.getLength(); 656 Object[] tmp = new Object[length]; 657 658 TypeArray methodOrdering = getMethodOrdering(); 659 if (methodOrdering.getLength() != length) { 660 // no ordering info present 661 for (int index = 0; index < length; index++) { 662 tmp[index] = methods.getObjAt(index); 663 } 664 } else { 665 for (int index = 0; index < length; index++) { 666 int originalIndex = getMethodOrdering().getIntAt(index); 667 tmp[originalIndex] = methods.getObjAt(index); 668 } 669 } 670 671 return Arrays.asList(tmp); 672 } 673 674 /** Return a List containing an SA InstanceKlass for each 675 interface named in this class's 'implements' clause. 676 */ 677 public List getDirectImplementedInterfaces() { 678 // Contains an InstanceKlass for each interface in this classes 679 // 'implements' clause. 680 681 ObjArray interfaces = getLocalInterfaces(); 682 int length = (int) interfaces.getLength(); 683 List directImplementedInterfaces = new ArrayList(length); 684 685 for (int index = 0; index < length; index ++) { 686 directImplementedInterfaces.add(interfaces.getObjAt(index)); 687 } 688 689 return directImplementedInterfaces; 690 } 691 692 693 public long getObjectSize() { 694 long bodySize = alignObjectOffset(getVtableLen() * getHeap().getOopSize()) 695 + alignObjectOffset(getItableLen() * getHeap().getOopSize()) 696 + (getStaticFieldSize() + getNonstaticOopMapSize()) * getHeap().getOopSize(); 697 return alignObjectSize(headerSize + bodySize); 698 } 699 700 public Klass arrayKlassImpl(boolean orNull, int n) { 701 // FIXME: in reflective system this would need to change to 702 // actually allocate 703 if (getArrayKlasses() == null) { return null; } 704 ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses(); 705 if (orNull) { 706 return oak.arrayKlassOrNull(n); 707 } 708 return oak.arrayKlass(n); 709 } 710 711 public Klass arrayKlassImpl(boolean orNull) { 712 return arrayKlassImpl(orNull, 1); 713 } 714 715 public String signature() { 716 return "L" + super.signature() + ";"; 717 } 718 719 /** Convenience routine taking Strings; lookup is done in 720 SymbolTable. */ 721 public Method findMethod(String name, String sig) { 722 SymbolTable syms = VM.getVM().getSymbolTable(); 723 Symbol nameSym = syms.probe(name); 724 Symbol sigSym = syms.probe(sig); 725 if (nameSym == null || sigSym == null) { 726 return null; 727 } 728 return findMethod(nameSym, sigSym); 729 } 730 731 /** Find method in vtable. */ 732 public Method findMethod(Symbol name, Symbol sig) { 733 return findMethod(getMethods(), name, sig); 734 } 735 736 /** Breakpoint support (see methods on methodOop for details) */ 737 public BreakpointInfo getBreakpoints() { 738 Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset()); 739 return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr); 740 } 741 742 //---------------------------------------------------------------------- 743 // Internals only below this point 744 // 745 746 private void visitField(OopVisitor visitor, FieldType type, int index) { 747 Field f = newField(index); 748 if (type.isOop()) { 749 visitor.doOop((OopField) f, false); 750 return; 751 } 752 if (type.isByte()) { 753 visitor.doByte((ByteField) f, false); 754 return; 755 } 756 if (type.isChar()) { 757 visitor.doChar((CharField) f, false); 758 return; 759 } 760 if (type.isDouble()) { 761 visitor.doDouble((DoubleField) f, false); 762 return; 763 } 764 if (type.isFloat()) { 765 visitor.doFloat((FloatField) f, false); 766 return; 767 } 768 if (type.isInt()) { 769 visitor.doInt((IntField) f, false); 770 return; 771 } 772 if (type.isLong()) { 773 visitor.doLong((LongField) f, false); 774 return; 775 } 776 if (type.isShort()) { 777 visitor.doShort((ShortField) f, false); 778 return; 779 } 780 if (type.isBoolean()) { 781 visitor.doBoolean((BooleanField) f, false); 782 return; 783 } 784 } 785 786 // Creates new field from index in fields TypeArray 787 private Field newField(int index) { 788 TypeArray fields = getFields(); 789 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); 790 FieldType type = new FieldType((Symbol) getConstants().getObjAt(signatureIndex)); 791 if (type.isOop()) { 792 if (VM.getVM().isCompressedOopsEnabled()) { 793 return new NarrowOopField(this, index); 794 } else { 795 return new OopField(this, index); 796 } 797 } 798 if (type.isByte()) { 799 return new ByteField(this, index); 800 } 801 if (type.isChar()) { 802 return new CharField(this, index); 803 } 804 if (type.isDouble()) { 805 return new DoubleField(this, index); 806 } 807 if (type.isFloat()) { 808 return new FloatField(this, index); 809 } 810 if (type.isInt()) { 811 return new IntField(this, index); 812 } 813 if (type.isLong()) { 814 return new LongField(this, index); 815 } 816 if (type.isShort()) { 817 return new ShortField(this, index); 818 } 819 if (type.isBoolean()) { 820 return new BooleanField(this, index); 821 } 822 throw new RuntimeException("Illegal field type at index " + index); 823 } 824 825 private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) { 826 int len = (int) methods.getLength(); 827 // methods are sorted, so do binary search 828 int l = 0; 829 int h = len - 1; 830 while (l <= h) { 831 int mid = (l + h) >> 1; 832 Method m = (Method) methods.getObjAt(mid); 833 int res = m.getName().fastCompare(name); 834 if (res == 0) { 835 // found matching name; do linear search to find matching signature 836 // first, quick check for common case 837 if (m.getSignature().equals(signature)) return m; 838 // search downwards through overloaded methods 839 int i; 840 for (i = mid - 1; i >= l; i--) { 841 Method m1 = (Method) methods.getObjAt(i); 842 if (!m1.getName().equals(name)) break; 843 if (m1.getSignature().equals(signature)) return m1; 844 } 845 // search upwards 846 for (i = mid + 1; i <= h; i++) { 847 Method m1 = (Method) methods.getObjAt(i); 848 if (!m1.getName().equals(name)) break; 849 if (m1.getSignature().equals(signature)) return m1; 850 } 851 // not found 852 if (Assert.ASSERTS_ENABLED) { 853 int index = linearSearch(methods, name, signature); 854 if (index != -1) { 855 throw new DebuggerException("binary search bug: should have found entry " + index); 856 } 857 } 858 return null; 859 } else if (res < 0) { 860 l = mid + 1; 861 } else { 862 h = mid - 1; 863 } 864 } 865 if (Assert.ASSERTS_ENABLED) { 866 int index = linearSearch(methods, name, signature); 867 if (index != -1) { 868 throw new DebuggerException("binary search bug: should have found entry " + index); 869 } 870 } 871 return null; 872 } 873 874 private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) { 875 int len = (int) methods.getLength(); 876 for (int index = 0; index < len; index++) { 877 Method m = (Method) methods.getObjAt(index); 878 if (m.getSignature().equals(signature) && m.getName().equals(name)) { 879 return index; 880 } 881 } 882 return -1; 883 } 884 }