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