1 /* 2 * Copyright (c) 2000, 2011, 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.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 = type.getAddressField("_source_file_name"); 86 sourceDebugExtension = type.getAddressField("_source_debug_extension"); 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 staticOopFieldCount = new CIntField(type.getCIntegerField("_static_oop_field_count"), 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 = type.getAddressField("_generic_signature"); 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 AddressField sourceFileName; 139 private static AddressField sourceDebugExtension; 140 private static OopField innerClasses; 141 private static CIntField nonstaticFieldSize; 142 private static CIntField staticFieldSize; 143 private static CIntField staticOopFieldCount; 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 AddressField 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 getSymbol(sourceFileName); } 261 public Symbol getSourceDebugExtension(){ return getSymbol(sourceDebugExtension); } 262 public TypeArray getInnerClasses() { return (TypeArray) innerClasses.getValue(this); } 263 public long getNonstaticFieldSize() { return nonstaticFieldSize.getValue(this); } 264 public long getStaticOopFieldCount() { return staticOopFieldCount.getValue(this); } 265 public long getNonstaticOopMapSize() { return nonstaticOopMapSize.getValue(this); } 266 public boolean getIsMarkedDependent() { return isMarkedDependent.getValue(this) != 0; } 267 public long getVtableLen() { return vtableLen.getValue(this); } 268 public long getItableLen() { return itableLen.getValue(this); } 269 public Symbol getGenericSignature() { return getSymbol(genericSignature); } 270 public long majorVersion() { return majorVersion.getValue(this); } 271 public long minorVersion() { return minorVersion.getValue(this); } 272 273 // "size helper" == instance size in words 274 public long getSizeHelper() { 275 int lh = getLayoutHelper(); 276 if (Assert.ASSERTS_ENABLED) { 277 Assert.that(lh > 0, "layout helper initialized for instance class"); 278 } 279 return lh / VM.getVM().getAddressSize(); 280 } 281 282 // same as enum InnerClassAttributeOffset in VM code. 283 public static interface InnerClassAttributeOffset { 284 // from JVM spec. "InnerClasses" attribute 285 public static final int innerClassInnerClassInfoOffset = 0; 286 public static final int innerClassOuterClassInfoOffset = 1; 287 public static final int innerClassInnerNameOffset = 2; 288 public static final int innerClassAccessFlagsOffset = 3; 289 public static final int innerClassNextOffset = 4; 290 }; 291 292 // refer to compute_modifier_flags in VM code. 293 public long computeModifierFlags() { 294 long access = getAccessFlags(); 295 // But check if it happens to be member class. 296 TypeArray innerClassList = getInnerClasses(); 297 int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength(); 298 if (length > 0) { 299 if (Assert.ASSERTS_ENABLED) { 300 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking"); 301 } 302 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { 303 int ioff = innerClassList.getShortAt(i + 304 InnerClassAttributeOffset.innerClassInnerClassInfoOffset); 305 // 'ioff' can be zero. 306 // refer to JVM spec. section 4.7.5. 307 if (ioff != 0) { 308 // only look at classes that are already loaded 309 // since we are looking for the flags for our self. 310 ConstantPool.CPSlot classInfo = getConstants().getSlotAt(ioff); 311 Symbol name = null; 312 if (classInfo.isOop()) { 313 name = ((Klass) classInfo.getOop()).getName(); 314 } else if (classInfo.isMetaData()) { 315 name = classInfo.getSymbol(); 316 } else { 317 throw new RuntimeException("should not reach here"); 318 } 319 320 if (name.equals(getName())) { 321 // This is really a member class 322 access = innerClassList.getShortAt(i + 323 InnerClassAttributeOffset.innerClassAccessFlagsOffset); 324 break; 325 } 326 } 327 } // for inner classes 328 } 329 330 // Remember to strip ACC_SUPER bit 331 return (access & (~JVM_ACC_SUPER)) & JVM_ACC_WRITTEN_FLAGS; 332 } 333 334 335 // whether given Symbol is name of an inner/nested Klass of this Klass? 336 // anonymous and local classes are excluded. 337 public boolean isInnerClassName(Symbol sym) { 338 return isInInnerClasses(sym, false); 339 } 340 341 // whether given Symbol is name of an inner/nested Klass of this Klass? 342 // anonymous classes excluded, but local classes are included. 343 public boolean isInnerOrLocalClassName(Symbol sym) { 344 return isInInnerClasses(sym, true); 345 } 346 347 private boolean isInInnerClasses(Symbol sym, boolean includeLocals) { 348 TypeArray innerClassList = getInnerClasses(); 349 int length = ( innerClassList == null)? 0 : (int) innerClassList.getLength(); 350 if (length > 0) { 351 if (Assert.ASSERTS_ENABLED) { 352 Assert.that(length % InnerClassAttributeOffset.innerClassNextOffset == 0, "just checking"); 353 } 354 for (int i = 0; i < length; i += InnerClassAttributeOffset.innerClassNextOffset) { 355 int ioff = innerClassList.getShortAt(i + 356 InnerClassAttributeOffset.innerClassInnerClassInfoOffset); 357 // 'ioff' can be zero. 358 // refer to JVM spec. section 4.7.5. 359 if (ioff != 0) { 360 ConstantPool.CPSlot iclassInfo = getConstants().getSlotAt(ioff); 361 Symbol innerName = null; 362 if (iclassInfo.isOop()) { 363 innerName = ((Klass) iclassInfo.getOop()).getName(); 364 } else if (iclassInfo.isMetaData()) { 365 innerName = iclassInfo.getSymbol(); 366 } else { 367 throw new RuntimeException("should not reach here"); 368 } 369 370 Symbol myname = getName(); 371 int ooff = innerClassList.getShortAt(i + 372 InnerClassAttributeOffset.innerClassOuterClassInfoOffset); 373 // for anonymous classes inner_name_index of InnerClasses 374 // attribute is zero. 375 int innerNameIndex = innerClassList.getShortAt(i + 376 InnerClassAttributeOffset.innerClassInnerNameOffset); 377 // if this is not a member (anonymous, local etc.), 'ooff' will be zero 378 // refer to JVM spec. section 4.7.5. 379 if (ooff == 0) { 380 if (includeLocals) { 381 // does it looks like my local class? 382 if (innerName.equals(sym) && 383 innerName.asString().startsWith(myname.asString())) { 384 // exclude anonymous classes. 385 return (innerNameIndex != 0); 386 } 387 } 388 } else { 389 ConstantPool.CPSlot oclassInfo = getConstants().getSlotAt(ooff); 390 Symbol outerName = null; 391 if (oclassInfo.isOop()) { 392 outerName = ((Klass) oclassInfo.getOop()).getName(); 393 } else if (oclassInfo.isMetaData()) { 394 outerName = oclassInfo.getSymbol(); 395 } else { 396 throw new RuntimeException("should not reach here"); 397 } 398 399 // include only if current class is outer class. 400 if (outerName.equals(myname) && innerName.equals(sym)) { 401 return true; 402 } 403 } 404 } 405 } // for inner classes 406 return false; 407 } else { 408 return false; 409 } 410 } 411 412 public boolean implementsInterface(Klass k) { 413 if (Assert.ASSERTS_ENABLED) { 414 Assert.that(k.isInterface(), "should not reach here"); 415 } 416 ObjArray interfaces = getTransitiveInterfaces(); 417 final int len = (int) interfaces.getLength(); 418 for (int i = 0; i < len; i++) { 419 if (interfaces.getObjAt(i).equals(k)) return true; 420 } 421 return false; 422 } 423 424 boolean computeSubtypeOf(Klass k) { 425 if (k.isInterface()) { 426 return implementsInterface(k); 427 } else { 428 return super.computeSubtypeOf(k); 429 } 430 } 431 432 public void printValueOn(PrintStream tty) { 433 tty.print("InstanceKlass for " + getName().asString()); 434 } 435 436 public void iterateFields(OopVisitor visitor, boolean doVMFields) { 437 super.iterateFields(visitor, doVMFields); 438 if (doVMFields) { 439 visitor.doOop(arrayKlasses, true); 440 visitor.doOop(methods, true); 441 visitor.doOop(methodOrdering, true); 442 visitor.doOop(localInterfaces, true); 443 visitor.doOop(transitiveInterfaces, true); 444 visitor.doCInt(nofImplementors, true); 445 for (int i = 0; i < IMPLEMENTORS_LIMIT; i++) 446 visitor.doOop(implementors[i], true); 447 visitor.doOop(fields, true); 448 visitor.doOop(constants, true); 449 visitor.doOop(classLoader, true); 450 visitor.doOop(protectionDomain, true); 451 visitor.doOop(signers, true); 452 visitor.doOop(innerClasses, true); 453 visitor.doCInt(nonstaticFieldSize, true); 454 visitor.doCInt(staticFieldSize, true); 455 visitor.doCInt(staticOopFieldCount, true); 456 visitor.doCInt(nonstaticOopMapSize, true); 457 visitor.doCInt(isMarkedDependent, true); 458 visitor.doCInt(initState, true); 459 visitor.doCInt(vtableLen, true); 460 visitor.doCInt(itableLen, true); 461 } 462 463 TypeArray fields = getFields(); 464 int length = (int) fields.getLength(); 465 for (int index = 0; index < length; index += NEXT_OFFSET) { 466 short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET); 467 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); 468 FieldType type = new FieldType(getConstants().getSymbolAt(signatureIndex)); 469 AccessFlags access = new AccessFlags(accessFlags); 470 if (access.isStatic()) { 471 visitField(visitor, type, index); 472 } 473 } 474 } 475 476 public Klass getJavaSuper() { 477 return getSuper(); 478 } 479 480 public void iterateNonStaticFields(OopVisitor visitor) { 481 if (getSuper() != null) { 482 ((InstanceKlass) getSuper()).iterateNonStaticFields(visitor); 483 } 484 TypeArray fields = getFields(); 485 486 int length = (int) fields.getLength(); 487 for (int index = 0; index < length; index += NEXT_OFFSET) { 488 short accessFlags = fields.getShortAt(index + ACCESS_FLAGS_OFFSET); 489 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); 490 491 FieldType type = new FieldType(getConstants().getSymbolAt(signatureIndex)); 492 AccessFlags access = new AccessFlags(accessFlags); 493 if (!access.isStatic()) { 494 visitField(visitor, type, index); 495 } 496 } 497 } 498 499 /** Field access by name. */ 500 public Field findLocalField(Symbol name, Symbol sig) { 501 TypeArray fields = getFields(); 502 int n = (int) fields.getLength(); 503 ConstantPool cp = getConstants(); 504 for (int i = 0; i < n; i += NEXT_OFFSET) { 505 int nameIndex = fields.getShortAt(i + NAME_INDEX_OFFSET); 506 int sigIndex = fields.getShortAt(i + SIGNATURE_INDEX_OFFSET); 507 Symbol f_name = cp.getSymbolAt(nameIndex); 508 Symbol f_sig = cp.getSymbolAt(sigIndex); 509 if (name.equals(f_name) && sig.equals(f_sig)) { 510 return newField(i); 511 } 512 } 513 514 return null; 515 } 516 517 /** Find field in direct superinterfaces. */ 518 public Field findInterfaceField(Symbol name, Symbol sig) { 519 ObjArray interfaces = getLocalInterfaces(); 520 int n = (int) interfaces.getLength(); 521 for (int i = 0; i < n; i++) { 522 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i); 523 if (Assert.ASSERTS_ENABLED) { 524 Assert.that(intf1.isInterface(), "just checking type"); 525 } 526 // search for field in current interface 527 Field f = intf1.findLocalField(name, sig); 528 if (f != null) { 529 if (Assert.ASSERTS_ENABLED) { 530 Assert.that(f.getAccessFlagsObj().isStatic(), "interface field must be static"); 531 } 532 return f; 533 } 534 // search for field in direct superinterfaces 535 f = intf1.findInterfaceField(name, sig); 536 if (f != null) return f; 537 } 538 // otherwise field lookup fails 539 return null; 540 } 541 542 /** Find field according to JVM spec 5.4.3.2, returns the klass in 543 which the field is defined. */ 544 public Field findField(Symbol name, Symbol sig) { 545 // search order according to newest JVM spec (5.4.3.2, p.167). 546 // 1) search for field in current klass 547 Field f = findLocalField(name, sig); 548 if (f != null) return f; 549 550 // 2) search for field recursively in direct superinterfaces 551 f = findInterfaceField(name, sig); 552 if (f != null) return f; 553 554 // 3) apply field lookup recursively if superclass exists 555 InstanceKlass supr = (InstanceKlass) getSuper(); 556 if (supr != null) return supr.findField(name, sig); 557 558 // 4) otherwise field lookup fails 559 return null; 560 } 561 562 /** Find field according to JVM spec 5.4.3.2, returns the klass in 563 which the field is defined (convenience routine) */ 564 public Field findField(String name, String sig) { 565 SymbolTable symbols = VM.getVM().getSymbolTable(); 566 Symbol nameSym = symbols.probe(name); 567 Symbol sigSym = symbols.probe(sig); 568 if (nameSym == null || sigSym == null) { 569 return null; 570 } 571 return findField(nameSym, sigSym); 572 } 573 574 /** Find field according to JVM spec 5.4.3.2, returns the klass in 575 which the field is defined (retained only for backward 576 compatibility with jdbx) */ 577 public Field findFieldDbg(String name, String sig) { 578 return findField(name, sig); 579 } 580 581 /** Get field by its index in the fields array. Only designed for 582 use in a debugging system. */ 583 public Field getFieldByIndex(int fieldArrayIndex) { 584 return newField(fieldArrayIndex); 585 } 586 587 588 /** Return a List of SA Fields for the fields declared in this class. 589 Inherited fields are not included. 590 Return an empty list if there are no fields declared in this class. 591 Only designed for use in a debugging system. */ 592 public List getImmediateFields() { 593 // A list of Fields for each field declared in this class/interface, 594 // not including inherited fields. 595 TypeArray fields = getFields(); 596 597 int length = (int) fields.getLength(); 598 List immediateFields = new ArrayList(length / NEXT_OFFSET); 599 for (int index = 0; index < length; index += NEXT_OFFSET) { 600 immediateFields.add(getFieldByIndex(index)); 601 } 602 603 return immediateFields; 604 } 605 606 /** Return a List of SA Fields for all the java fields in this class, 607 including all inherited fields. This includes hidden 608 fields. Thus the returned list can contain fields with 609 the same name. 610 Return an empty list if there are no fields. 611 Only designed for use in a debugging system. */ 612 public List getAllFields() { 613 // Contains a Field for each field in this class, including immediate 614 // fields and inherited fields. 615 List allFields = getImmediateFields(); 616 617 // transitiveInterfaces contains all interfaces implemented 618 // by this class and its superclass chain with no duplicates. 619 620 ObjArray interfaces = getTransitiveInterfaces(); 621 int n = (int) interfaces.getLength(); 622 for (int i = 0; i < n; i++) { 623 InstanceKlass intf1 = (InstanceKlass) interfaces.getObjAt(i); 624 if (Assert.ASSERTS_ENABLED) { 625 Assert.that(intf1.isInterface(), "just checking type"); 626 } 627 allFields.addAll(intf1.getImmediateFields()); 628 } 629 630 // Get all fields in the superclass, recursively. But, don't 631 // include fields in interfaces implemented by superclasses; 632 // we already have all those. 633 if (!isInterface()) { 634 InstanceKlass supr; 635 if ( (supr = (InstanceKlass) getSuper()) != null) { 636 allFields.addAll(supr.getImmediateFields()); 637 } 638 } 639 640 return allFields; 641 } 642 643 644 /** Return a List of SA Methods declared directly in this class/interface. 645 Return an empty list if there are none, or if this isn't a class/ 646 interface. 647 */ 648 public List getImmediateMethods() { 649 // Contains a Method for each method declared in this class/interface 650 // not including inherited methods. 651 652 ObjArray methods = getMethods(); 653 int length = (int)methods.getLength(); 654 Object[] tmp = new Object[length]; 655 656 TypeArray methodOrdering = getMethodOrdering(); 657 if (methodOrdering.getLength() != length) { 658 // no ordering info present 659 for (int index = 0; index < length; index++) { 660 tmp[index] = methods.getObjAt(index); 661 } 662 } else { 663 for (int index = 0; index < length; index++) { 664 int originalIndex = getMethodOrdering().getIntAt(index); 665 tmp[originalIndex] = methods.getObjAt(index); 666 } 667 } 668 669 return Arrays.asList(tmp); 670 } 671 672 /** Return a List containing an SA InstanceKlass for each 673 interface named in this class's 'implements' clause. 674 */ 675 public List getDirectImplementedInterfaces() { 676 // Contains an InstanceKlass for each interface in this classes 677 // 'implements' clause. 678 679 ObjArray interfaces = getLocalInterfaces(); 680 int length = (int) interfaces.getLength(); 681 List directImplementedInterfaces = new ArrayList(length); 682 683 for (int index = 0; index < length; index ++) { 684 directImplementedInterfaces.add(interfaces.getObjAt(index)); 685 } 686 687 return directImplementedInterfaces; 688 } 689 690 691 public long getObjectSize() { 692 long bodySize = alignObjectOffset(getVtableLen() * getHeap().getOopSize()) 693 + alignObjectOffset(getItableLen() * getHeap().getOopSize()) 694 + (getNonstaticOopMapSize()) * getHeap().getOopSize(); 695 return alignObjectSize(headerSize + bodySize); 696 } 697 698 public Klass arrayKlassImpl(boolean orNull, int n) { 699 // FIXME: in reflective system this would need to change to 700 // actually allocate 701 if (getArrayKlasses() == null) { return null; } 702 ObjArrayKlass oak = (ObjArrayKlass) getArrayKlasses(); 703 if (orNull) { 704 return oak.arrayKlassOrNull(n); 705 } 706 return oak.arrayKlass(n); 707 } 708 709 public Klass arrayKlassImpl(boolean orNull) { 710 return arrayKlassImpl(orNull, 1); 711 } 712 713 public String signature() { 714 return "L" + super.signature() + ";"; 715 } 716 717 /** Convenience routine taking Strings; lookup is done in 718 SymbolTable. */ 719 public Method findMethod(String name, String sig) { 720 SymbolTable syms = VM.getVM().getSymbolTable(); 721 Symbol nameSym = syms.probe(name); 722 Symbol sigSym = syms.probe(sig); 723 if (nameSym == null || sigSym == null) { 724 return null; 725 } 726 return findMethod(nameSym, sigSym); 727 } 728 729 /** Find method in vtable. */ 730 public Method findMethod(Symbol name, Symbol sig) { 731 return findMethod(getMethods(), name, sig); 732 } 733 734 /** Breakpoint support (see methods on methodOop for details) */ 735 public BreakpointInfo getBreakpoints() { 736 Address addr = getHandle().getAddressAt(Oop.getHeaderSize() + breakpoints.getOffset()); 737 return (BreakpointInfo) VMObjectFactory.newObject(BreakpointInfo.class, addr); 738 } 739 740 //---------------------------------------------------------------------- 741 // Internals only below this point 742 // 743 744 private void visitField(OopVisitor visitor, FieldType type, int index) { 745 Field f = newField(index); 746 if (type.isOop()) { 747 visitor.doOop((OopField) f, false); 748 return; 749 } 750 if (type.isByte()) { 751 visitor.doByte((ByteField) f, false); 752 return; 753 } 754 if (type.isChar()) { 755 visitor.doChar((CharField) f, false); 756 return; 757 } 758 if (type.isDouble()) { 759 visitor.doDouble((DoubleField) f, false); 760 return; 761 } 762 if (type.isFloat()) { 763 visitor.doFloat((FloatField) f, false); 764 return; 765 } 766 if (type.isInt()) { 767 visitor.doInt((IntField) f, false); 768 return; 769 } 770 if (type.isLong()) { 771 visitor.doLong((LongField) f, false); 772 return; 773 } 774 if (type.isShort()) { 775 visitor.doShort((ShortField) f, false); 776 return; 777 } 778 if (type.isBoolean()) { 779 visitor.doBoolean((BooleanField) f, false); 780 return; 781 } 782 } 783 784 // Creates new field from index in fields TypeArray 785 private Field newField(int index) { 786 TypeArray fields = getFields(); 787 short signatureIndex = fields.getShortAt(index + SIGNATURE_INDEX_OFFSET); 788 FieldType type = new FieldType(getConstants().getSymbolAt(signatureIndex)); 789 if (type.isOop()) { 790 if (VM.getVM().isCompressedOopsEnabled()) { 791 return new NarrowOopField(this, index); 792 } else { 793 return new OopField(this, index); 794 } 795 } 796 if (type.isByte()) { 797 return new ByteField(this, index); 798 } 799 if (type.isChar()) { 800 return new CharField(this, index); 801 } 802 if (type.isDouble()) { 803 return new DoubleField(this, index); 804 } 805 if (type.isFloat()) { 806 return new FloatField(this, index); 807 } 808 if (type.isInt()) { 809 return new IntField(this, index); 810 } 811 if (type.isLong()) { 812 return new LongField(this, index); 813 } 814 if (type.isShort()) { 815 return new ShortField(this, index); 816 } 817 if (type.isBoolean()) { 818 return new BooleanField(this, index); 819 } 820 throw new RuntimeException("Illegal field type at index " + index); 821 } 822 823 private static Method findMethod(ObjArray methods, Symbol name, Symbol signature) { 824 int len = (int) methods.getLength(); 825 // methods are sorted, so do binary search 826 int l = 0; 827 int h = len - 1; 828 while (l <= h) { 829 int mid = (l + h) >> 1; 830 Method m = (Method) methods.getObjAt(mid); 831 int res = m.getName().fastCompare(name); 832 if (res == 0) { 833 // found matching name; do linear search to find matching signature 834 // first, quick check for common case 835 if (m.getSignature().equals(signature)) return m; 836 // search downwards through overloaded methods 837 int i; 838 for (i = mid - 1; i >= l; i--) { 839 Method m1 = (Method) methods.getObjAt(i); 840 if (!m1.getName().equals(name)) break; 841 if (m1.getSignature().equals(signature)) return m1; 842 } 843 // search upwards 844 for (i = mid + 1; i <= h; i++) { 845 Method m1 = (Method) methods.getObjAt(i); 846 if (!m1.getName().equals(name)) break; 847 if (m1.getSignature().equals(signature)) return m1; 848 } 849 // not found 850 if (Assert.ASSERTS_ENABLED) { 851 int index = linearSearch(methods, name, signature); 852 if (index != -1) { 853 throw new DebuggerException("binary search bug: should have found entry " + index); 854 } 855 } 856 return null; 857 } else if (res < 0) { 858 l = mid + 1; 859 } else { 860 h = mid - 1; 861 } 862 } 863 if (Assert.ASSERTS_ENABLED) { 864 int index = linearSearch(methods, name, signature); 865 if (index != -1) { 866 throw new DebuggerException("binary search bug: should have found entry " + index); 867 } 868 } 869 return null; 870 } 871 872 private static int linearSearch(ObjArray methods, Symbol name, Symbol signature) { 873 int len = (int) methods.getLength(); 874 for (int index = 0; index < len; index++) { 875 Method m = (Method) methods.getObjAt(index); 876 if (m.getSignature().equals(signature) && m.getName().equals(name)) { 877 return index; 878 } 879 } 880 return -1; 881 } 882 }