1 /* 2 * Copyright (c) 2002, 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.jdi; 26 27 import java.io.*; 28 29 import com.sun.jdi.*; 30 31 import sun.jvm.hotspot.memory.SystemDictionary; 32 import sun.jvm.hotspot.oops.Instance; 33 import sun.jvm.hotspot.oops.InstanceKlass; 34 import sun.jvm.hotspot.oops.ArrayKlass; 35 import sun.jvm.hotspot.oops.JVMDIClassStatus; 36 import sun.jvm.hotspot.oops.Klass; 37 import sun.jvm.hotspot.oops.ObjArray; 38 import sun.jvm.hotspot.oops.Oop; 39 import sun.jvm.hotspot.oops.Symbol; 40 import sun.jvm.hotspot.oops.DefaultHeapVisitor; 41 import sun.jvm.hotspot.utilities.Assert; 42 43 import java.util.*; 44 import java.lang.ref.SoftReference; 45 46 public abstract class ReferenceTypeImpl extends TypeImpl 47 implements ReferenceType { 48 protected Klass saKlass; // This can be an InstanceKlass or an ArrayKlass 49 protected Symbol typeNameSymbol; // This is used in vm.classesByName to speedup search 50 private int modifiers = -1; 51 private String signature = null; 52 private SoftReference sdeRef = null; 53 private SoftReference fieldsCache; 54 private SoftReference allFieldsCache; 55 private SoftReference methodsCache; 56 private SoftReference allMethodsCache; 57 private SoftReference nestedTypesCache; 58 private SoftReference methodInvokesCache; 59 60 /* to mark when no info available */ 61 static final SDE NO_SDE_INFO_MARK = new SDE(); 62 63 protected ReferenceTypeImpl(VirtualMachine aVm, sun.jvm.hotspot.oops.Klass klass) { 64 super(aVm); 65 saKlass = klass; 66 typeNameSymbol = saKlass.getName(); 67 if (Assert.ASSERTS_ENABLED) { 68 Assert.that(typeNameSymbol != null, "null type name for a Klass"); 69 } 70 } 71 72 Symbol typeNameAsSymbol() { 73 return typeNameSymbol; 74 } 75 76 Method getMethodMirror(sun.jvm.hotspot.oops.Method ref) { 77 // SA creates new Method objects when they are referenced which means 78 // that the incoming object might not be the same object as on our 79 // even though it is the same method. So do an address compare by 80 // calling equals rather than just reference compare. 81 Iterator it = methods().iterator(); 82 while (it.hasNext()) { 83 MethodImpl method = (MethodImpl)it.next(); 84 if (ref.equals(method.ref())) { 85 return method; 86 } 87 } 88 if (ref.getMethodHolder().equals(SystemDictionary.getMethodHandleKlass())) { 89 // invoke methods are generated as needed, so make mirrors as needed 90 List mis = null; 91 if (methodInvokesCache == null) { 92 mis = new ArrayList(); 93 methodInvokesCache = new SoftReference(mis); 94 } else { 95 mis = (List)methodInvokesCache.get(); 96 } 97 it = mis.iterator(); 98 while (it.hasNext()) { 99 MethodImpl method = (MethodImpl)it.next(); 100 if (ref.equals(method.ref())) { 101 return method; 102 } 103 } 104 105 MethodImpl method = MethodImpl.createMethodImpl(vm, this, ref); 106 mis.add(method); 107 return method; 108 } 109 throw new IllegalArgumentException("Invalid method id: " + ref); 110 } 111 112 public boolean equals(Object obj) { 113 if ((obj != null) && (obj instanceof ReferenceTypeImpl)) { 114 ReferenceTypeImpl other = (ReferenceTypeImpl)obj; 115 return (ref().equals(other.ref())) && 116 (vm.equals(other.virtualMachine())); 117 } else { 118 return false; 119 } 120 } 121 122 public int hashCode() { 123 return saKlass.hashCode(); 124 } 125 126 public int compareTo(ReferenceType refType) { 127 /* 128 * Note that it is critical that compareTo() == 0 129 * implies that equals() == true. Otherwise, TreeSet 130 * will collapse classes. 131 * 132 * (Classes of the same name loaded by different class loaders 133 * or in different VMs must not return 0). 134 */ 135 ReferenceTypeImpl other = (ReferenceTypeImpl)refType; 136 int comp = name().compareTo(other.name()); 137 if (comp == 0) { 138 Oop rf1 = ref(); 139 Oop rf2 = other.ref(); 140 // optimize for typical case: refs equal and VMs equal 141 if (rf1.equals(rf2)) { 142 // sequenceNumbers are always positive 143 comp = vm.sequenceNumber - 144 ((VirtualMachineImpl)(other.virtualMachine())).sequenceNumber; 145 } else { 146 comp = rf1.getHandle().minus(rf2.getHandle()) < 0? -1 : 1; 147 } 148 } 149 return comp; 150 } 151 152 public String signature() { 153 if (signature == null) { 154 signature = saKlass.signature(); 155 } 156 return signature; 157 } 158 159 // refer to JvmtiEnv::GetClassSignature. 160 // null is returned for array klasses. 161 public String genericSignature() { 162 if (saKlass instanceof ArrayKlass) { 163 return null; 164 } else { 165 Symbol genSig = ((InstanceKlass)saKlass).getGenericSignature(); 166 return (genSig != null)? genSig.asString() : null; 167 } 168 } 169 170 public ClassLoaderReference classLoader() { 171 Instance xx = (Instance)(((InstanceKlass)saKlass).getClassLoader()); 172 return (ClassLoaderReferenceImpl)vm.classLoaderMirror(xx); 173 } 174 175 public boolean isPublic() { 176 return((modifiers() & VMModifiers.PUBLIC) != 0); 177 } 178 179 public boolean isProtected() { 180 return((modifiers() & VMModifiers.PROTECTED) != 0); 181 } 182 183 public boolean isPrivate() { 184 return((modifiers() & VMModifiers.PRIVATE) != 0); 185 } 186 187 public boolean isPackagePrivate() { 188 return !isPublic() && !isPrivate() && !isProtected(); 189 } 190 191 public boolean isAbstract() { 192 return((modifiers() & VMModifiers.ABSTRACT) != 0); 193 } 194 195 public boolean isFinal() { 196 return((modifiers() & VMModifiers.FINAL) != 0); 197 } 198 199 public boolean isStatic() { 200 return((modifiers() & VMModifiers.STATIC) != 0); 201 } 202 203 public boolean isPrepared() { 204 return (saKlass.getClassStatus() & JVMDIClassStatus.PREPARED) != 0; 205 } 206 207 final void checkPrepared() throws ClassNotPreparedException { 208 if (! isPrepared()) { 209 throw new ClassNotPreparedException(); 210 } 211 } 212 213 public boolean isVerified() { 214 return (saKlass.getClassStatus() & JVMDIClassStatus.VERIFIED) != 0; 215 } 216 217 public boolean isInitialized() { 218 return (saKlass.getClassStatus() & JVMDIClassStatus.INITIALIZED) != 0; 219 } 220 221 public boolean failedToInitialize() { 222 return (saKlass.getClassStatus() & JVMDIClassStatus.ERROR) != 0; 223 } 224 225 private boolean isThrowableBacktraceField(sun.jvm.hotspot.oops.Field fld) { 226 // refer to JvmtiEnv::GetClassFields in jvmtiEnv.cpp. 227 // We want to filter out java.lang.Throwable.backtrace (see 4446677). 228 // It contains some methodOops that aren't quite real Objects. 229 if (fld.getFieldHolder().getName().equals(vm.javaLangThrowable()) && 230 fld.getID().getName().equals("backtrace")) { 231 return true; 232 } else { 233 return false; 234 } 235 } 236 237 public final List fields() throws ClassNotPreparedException { 238 List fields = (fieldsCache != null)? (List) fieldsCache.get() : null; 239 if (fields == null) { 240 checkPrepared(); 241 if (saKlass instanceof ArrayKlass) { 242 fields = new ArrayList(0); 243 } else { 244 // Get a list of the sa Field types 245 List saFields = ((InstanceKlass)saKlass).getImmediateFields(); 246 247 // Create a list of our Field types 248 int len = saFields.size(); 249 fields = new ArrayList(len); 250 for (int ii = 0; ii < len; ii++) { 251 sun.jvm.hotspot.oops.Field curField = (sun.jvm.hotspot.oops.Field)saFields.get(ii); 252 if (! isThrowableBacktraceField(curField)) { 253 fields.add(new FieldImpl(vm, this, curField)); 254 } 255 } 256 } 257 fields = Collections.unmodifiableList(fields); 258 fieldsCache = new SoftReference(fields); 259 } 260 return fields; 261 } 262 263 public final List allFields() throws ClassNotPreparedException { 264 List allFields = (allFieldsCache != null)? (List) allFieldsCache.get() : null; 265 if (allFields == null) { 266 checkPrepared(); 267 if (saKlass instanceof ArrayKlass) { 268 // is 'length' a field of array klasses? To maintain 269 // consistency with JVMDI-JDI we return 0 size. 270 allFields = new ArrayList(0); 271 } else { 272 List saFields; 273 274 // Get a list of the sa Field types 275 saFields = ((InstanceKlass)saKlass).getAllFields(); 276 277 // Create a list of our Field types 278 int len = saFields.size(); 279 allFields = new ArrayList(len); 280 for (int ii = 0; ii < len; ii++) { 281 sun.jvm.hotspot.oops.Field curField = (sun.jvm.hotspot.oops.Field)saFields.get(ii); 282 if (! isThrowableBacktraceField(curField)) { 283 allFields.add(new FieldImpl(vm, vm.referenceType(curField.getFieldHolder()), curField)); 284 } 285 } 286 } 287 allFields = Collections.unmodifiableList(allFields); 288 allFieldsCache = new SoftReference(allFields); 289 } 290 return allFields; 291 } 292 293 abstract List inheritedTypes(); 294 295 void addVisibleFields(List visibleList, Map visibleTable, List ambiguousNames) { 296 List list = visibleFields(); 297 Iterator iter = list.iterator(); 298 while (iter.hasNext()) { 299 Field field = (Field)iter.next(); 300 String name = field.name(); 301 if (!ambiguousNames.contains(name)) { 302 Field duplicate = (Field)visibleTable.get(name); 303 if (duplicate == null) { 304 visibleList.add(field); 305 visibleTable.put(name, field); 306 } else if (!field.equals(duplicate)) { 307 ambiguousNames.add(name); 308 visibleTable.remove(name); 309 visibleList.remove(duplicate); 310 } else { 311 // identical field from two branches; do nothing 312 } 313 } 314 } 315 } 316 317 public final List visibleFields() throws ClassNotPreparedException { 318 checkPrepared(); 319 /* 320 * Maintain two different collections of visible fields. The 321 * list maintains a reasonable order for return. The 322 * hash map provides an efficient way to lookup visible fields 323 * by name, important for finding hidden or ambiguous fields. 324 */ 325 List visibleList = new ArrayList(); 326 Map visibleTable = new HashMap(); 327 328 /* Track fields removed from above collection due to ambiguity */ 329 List ambiguousNames = new ArrayList(); 330 331 /* Add inherited, visible fields */ 332 List types = inheritedTypes(); 333 Iterator iter = types.iterator(); 334 while (iter.hasNext()) { 335 /* 336 * TO DO: Be defensive and check for cyclic interface inheritance 337 */ 338 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); 339 type.addVisibleFields(visibleList, visibleTable, ambiguousNames); 340 } 341 342 /* 343 * Insert fields from this type, removing any inherited fields they 344 * hide. 345 */ 346 List retList = new ArrayList(fields()); 347 iter = retList.iterator(); 348 while (iter.hasNext()) { 349 Field field = (Field)iter.next(); 350 Field hidden = (Field)visibleTable.get(field.name()); 351 if (hidden != null) { 352 visibleList.remove(hidden); 353 } 354 } 355 retList.addAll(visibleList); 356 return retList; 357 } 358 359 public final Field fieldByName(String fieldName) throws ClassNotPreparedException { 360 java.util.List searchList; 361 Field f; 362 363 // visibleFields calls checkPrepared 364 searchList = visibleFields(); 365 366 for (int i=0; i<searchList.size(); i++) { 367 f = (Field)searchList.get(i); 368 369 if (f.name().equals(fieldName)) { 370 return f; 371 } 372 } 373 //throw new NoSuchFieldException("Field '" + fieldName + "' not found in " + name()); 374 return null; 375 } 376 377 public final List methods() throws ClassNotPreparedException { 378 List methods = (methodsCache != null)? (List) methodsCache.get() : null; 379 if (methods == null) { 380 checkPrepared(); 381 if (saKlass instanceof ArrayKlass) { 382 methods = new ArrayList(0); 383 } else { 384 List saMethods; 385 // Get a list of the SA Method types 386 saMethods = ((InstanceKlass)saKlass).getImmediateMethods(); 387 388 // Create a list of our MethodImpl types 389 int len = saMethods.size(); 390 methods = new ArrayList(len); 391 for (int ii = 0; ii < len; ii++) { 392 methods.add(MethodImpl.createMethodImpl(vm, this, (sun.jvm.hotspot.oops.Method)saMethods.get(ii))); 393 } 394 } 395 methods = Collections.unmodifiableList(methods); 396 methodsCache = new SoftReference(methods); 397 } 398 return methods; 399 } 400 401 abstract List getAllMethods(); 402 public final List allMethods() throws ClassNotPreparedException { 403 List allMethods = (allMethodsCache != null)? (List) allMethodsCache.get() : null; 404 if (allMethods == null) { 405 checkPrepared(); 406 allMethods = Collections.unmodifiableList(getAllMethods()); 407 allMethodsCache = new SoftReference(allMethods); 408 } 409 return allMethods; 410 } 411 412 /* 413 * Utility method used by subclasses to build lists of visible 414 * methods. 415 */ 416 void addToMethodMap(Map methodMap, List methodList) { 417 Iterator iter = methodList.iterator(); 418 while (iter.hasNext()) { 419 Method method = (Method)iter.next(); 420 methodMap.put(method.name().concat(method.signature()), method); 421 } 422 } 423 424 abstract void addVisibleMethods(Map methodMap); 425 public final List visibleMethods() throws ClassNotPreparedException { 426 checkPrepared(); 427 /* 428 * Build a collection of all visible methods. The hash 429 * map allows us to do this efficiently by keying on the 430 * concatenation of name and signature. 431 */ 432 //System.out.println("jj: RTI: Calling addVisibleMethods for:" + this); 433 Map map = new HashMap(); 434 addVisibleMethods(map); 435 436 /* 437 * ... but the hash map destroys order. Methods should be 438 * returned in a sensible order, as they are in allMethods(). 439 * So, start over with allMethods() and use the hash map 440 * to filter that ordered collection. 441 */ 442 //System.out.println("jj: RTI: Calling allMethods for:" + this); 443 444 List list = new ArrayList(allMethods()); 445 //System.out.println("jj: allMethods = " + jjstr(list)); 446 //System.out.println("jj: map = " + map.toString()); 447 //System.out.println("jj: map = " + jjstr(map.values())); 448 list.retainAll(map.values()); 449 //System.out.println("jj: map = " + jjstr(list)); 450 //System.exit(0); 451 return list; 452 } 453 454 static Object prev; 455 456 static public String jjstr(Collection cc) { 457 StringBuffer buf = new StringBuffer(); 458 buf.append("["); 459 Iterator i = cc.iterator(); 460 boolean hasNext = i.hasNext(); 461 while (hasNext) { 462 Object o = i.next(); 463 if (prev == null) { 464 prev = o; 465 } else { 466 System.out.println("prev == curr?" + prev.equals(o)); 467 System.out.println("prev == curr?" + (prev == o)); 468 } 469 buf.append( o + "@" + o.hashCode()); 470 //buf.append( ((Object)o).toString()); 471 hasNext = i.hasNext(); 472 if (hasNext) 473 buf.append(", "); 474 } 475 476 buf.append("]"); 477 return buf.toString(); 478 } 479 480 public final List methodsByName(String name) throws ClassNotPreparedException { 481 // visibleMethods calls checkPrepared 482 List methods = visibleMethods(); 483 ArrayList retList = new ArrayList(methods.size()); 484 Iterator iter = methods.iterator(); 485 while (iter.hasNext()) { 486 Method candidate = (Method)iter.next(); 487 if (candidate.name().equals(name)) { 488 retList.add(candidate); 489 } 490 } 491 retList.trimToSize(); 492 return retList; 493 } 494 495 public final List methodsByName(String name, String signature) throws ClassNotPreparedException { 496 // visibleMethods calls checkPrepared 497 List methods = visibleMethods(); 498 ArrayList retList = new ArrayList(methods.size()); 499 Iterator iter = methods.iterator(); 500 while (iter.hasNext()) { 501 Method candidate = (Method)iter.next(); 502 if (candidate.name().equals(name) && 503 candidate.signature().equals(signature)) { 504 retList.add(candidate); 505 } 506 } 507 retList.trimToSize(); 508 return retList; 509 } 510 511 512 List getInterfaces() { 513 List myInterfaces; 514 if (saKlass instanceof ArrayKlass) { 515 // Actually, JLS says arrays implement Cloneable and Serializable 516 // But, JVMDI-JDI just returns 0 interfaces for arrays. We follow 517 // the same for consistency. 518 myInterfaces = new ArrayList(0); 519 } else { 520 // Get a list of the sa InstanceKlass types 521 List saInterfaces = ((InstanceKlass)saKlass).getDirectImplementedInterfaces(); 522 523 // Create a list of our InterfaceTypes 524 int len = saInterfaces.size(); 525 myInterfaces = new ArrayList(len); 526 for (int ii = 0; ii < len; ii++) { 527 myInterfaces.add(new InterfaceTypeImpl(vm, (InstanceKlass)saInterfaces.get(ii))); 528 } 529 } 530 return myInterfaces; 531 } 532 533 public final List nestedTypes() { 534 List nestedTypes = (nestedTypesCache != null)? (List) nestedTypesCache.get() : null; 535 if (nestedTypes == null) { 536 if (saKlass instanceof ArrayKlass) { 537 nestedTypes = new ArrayList(0); 538 } else { 539 ClassLoaderReference cl = classLoader(); 540 List classes = null; 541 if (cl != null) { 542 classes = cl.visibleClasses(); 543 } else { 544 classes = vm.bootstrapClasses(); 545 } 546 nestedTypes = new ArrayList(); 547 Iterator iter = classes.iterator(); 548 while (iter.hasNext()) { 549 ReferenceTypeImpl refType = (ReferenceTypeImpl)iter.next(); 550 Symbol candidateName = refType.ref().getName(); 551 if (((InstanceKlass)saKlass).isInnerOrLocalClassName(candidateName)) { 552 nestedTypes.add(refType); 553 } 554 } 555 } 556 nestedTypes = Collections.unmodifiableList(nestedTypes); 557 nestedTypesCache = new SoftReference(nestedTypes); 558 } 559 return nestedTypes; 560 } 561 562 public Value getValue(Field sig) { 563 List list = new ArrayList(1); 564 list.add(sig); 565 Map map = getValues(list); 566 return(Value)map.get(sig); 567 } 568 569 /** 570 * Returns a map of field values 571 */ 572 public Map getValues(List theFields) { 573 //validateMirrors(); 574 int size = theFields.size(); 575 Map map = new HashMap(size); 576 for (int ii=0; ii<size; ii++) { 577 FieldImpl fieldImpl = (FieldImpl)theFields.get(ii); 578 579 validateFieldAccess(fieldImpl); 580 // Do more validation specific to ReferenceType field getting 581 if (!fieldImpl.isStatic()) { 582 throw new IllegalArgumentException( 583 "Attempt to use non-static field with ReferenceType: " + 584 fieldImpl.name()); 585 } 586 map.put(fieldImpl, fieldImpl.getValue()); 587 } 588 return map; 589 } 590 591 void validateFieldAccess(Field field) { 592 /* 593 * Field must be in this object's class, a superclass, or 594 * implemented interface 595 */ 596 ReferenceTypeImpl declType = (ReferenceTypeImpl)field.declaringType(); 597 if (!declType.isAssignableFrom(this)) { 598 throw new IllegalArgumentException("Invalid field"); 599 } 600 } 601 602 public ClassObjectReference classObject() { 603 return vm.classObjectMirror(ref().getJavaMirror()); 604 } 605 606 SDE.Stratum stratum(String stratumID) { 607 SDE sde = sourceDebugExtensionInfo(); 608 if (!sde.isValid()) { 609 sde = NO_SDE_INFO_MARK; 610 } 611 return sde.stratum(stratumID); 612 } 613 614 public String sourceName() throws AbsentInformationException { 615 return (String)(sourceNames(vm.getDefaultStratum()).get(0)); 616 } 617 618 public List sourceNames(String stratumID) 619 throws AbsentInformationException { 620 SDE.Stratum stratum = stratum(stratumID); 621 if (stratum.isJava()) { 622 List result = new ArrayList(1); 623 result.add(baseSourceName()); 624 return result; 625 } 626 return stratum.sourceNames(this); 627 } 628 629 public List sourcePaths(String stratumID) 630 throws AbsentInformationException { 631 SDE.Stratum stratum = stratum(stratumID); 632 if (stratum.isJava()) { 633 List result = new ArrayList(1); 634 result.add(baseSourceDir() + baseSourceName()); 635 return result; 636 } 637 return stratum.sourcePaths(this); 638 } 639 640 String baseSourceName() throws AbsentInformationException { 641 if (saKlass instanceof ArrayKlass) { 642 throw new AbsentInformationException(); 643 } 644 Symbol sym = ((InstanceKlass)saKlass).getSourceFileName(); 645 if (sym != null) { 646 return sym.asString(); 647 } else { 648 throw new AbsentInformationException(); 649 } 650 } 651 652 String baseSourcePath() throws AbsentInformationException { 653 return baseSourceDir() + baseSourceName(); 654 } 655 656 String baseSourceDir() { 657 String typeName = name(); 658 StringBuffer sb = new StringBuffer(typeName.length() + 10); 659 int index = 0; 660 int nextIndex; 661 662 while ((nextIndex = typeName.indexOf('.', index)) > 0) { 663 sb.append(typeName.substring(index, nextIndex)); 664 sb.append(java.io.File.separatorChar); 665 index = nextIndex + 1; 666 } 667 return sb.toString(); 668 } 669 670 public String sourceDebugExtension() 671 throws AbsentInformationException { 672 if (!vm.canGetSourceDebugExtension()) { 673 throw new UnsupportedOperationException(); 674 } 675 SDE sde = sourceDebugExtensionInfo(); 676 if (sde == NO_SDE_INFO_MARK) { 677 throw new AbsentInformationException(); 678 } 679 return sde.sourceDebugExtension; 680 } 681 682 private SDE sourceDebugExtensionInfo() { 683 if (!vm.canGetSourceDebugExtension()) { 684 return NO_SDE_INFO_MARK; 685 } 686 SDE sde = null; 687 sde = (sdeRef == null) ? null : (SDE)sdeRef.get(); 688 if (sde == null) { 689 String extension = null; 690 if (saKlass instanceof InstanceKlass) { 691 Symbol sdeSym = ((InstanceKlass)saKlass).getSourceDebugExtension(); 692 extension = (sdeSym != null)? sdeSym.asString() : null; 693 } 694 if (extension == null) { 695 sde = NO_SDE_INFO_MARK; 696 } else { 697 sde = new SDE(extension); 698 } 699 sdeRef = new SoftReference(sde); 700 } 701 return sde; 702 } 703 704 public List availableStrata() { 705 SDE sde = sourceDebugExtensionInfo(); 706 if (sde.isValid()) { 707 return sde.availableStrata(); 708 } else { 709 List strata = new ArrayList(); 710 strata.add(SDE.BASE_STRATUM_NAME); 711 return strata; 712 } 713 } 714 715 /** 716 * Always returns non-null stratumID 717 */ 718 public String defaultStratum() { 719 SDE sdei = sourceDebugExtensionInfo(); 720 if (sdei.isValid()) { 721 return sdei.defaultStratumId; 722 } else { 723 return SDE.BASE_STRATUM_NAME; 724 } 725 } 726 727 public final int modifiers() { 728 if (modifiers == -1) { 729 modifiers = getModifiers(); 730 } 731 return modifiers; 732 } 733 734 // new method since 1.6. 735 // Real body will be supplied later. 736 public List instances(long maxInstances) { 737 if (!vm.canGetInstanceInfo()) { 738 throw new UnsupportedOperationException( 739 "target does not support getting instances"); 740 } 741 742 if (maxInstances < 0) { 743 throw new IllegalArgumentException("maxInstances is less than zero: " 744 + maxInstances); 745 } 746 747 final List objects = new ArrayList(0); 748 if (isAbstract() || (this instanceof InterfaceType)) { 749 return objects; 750 } 751 752 final Klass givenKls = this.ref(); 753 final long max = maxInstances; 754 vm.saObjectHeap().iterate(new DefaultHeapVisitor() { 755 private long instCount=0; 756 public boolean doObj(Oop oop) { 757 if (givenKls.equals(oop.getKlass())) { 758 objects.add(vm.objectMirror(oop)); 759 instCount++; 760 } 761 if (max > 0 && instCount >= max) { 762 return true; 763 } 764 return false; 765 } 766 }); 767 return objects; 768 } 769 770 int getModifiers() { 771 return (int) saKlass.getClassModifiers(); 772 } 773 774 public List allLineLocations() 775 throws AbsentInformationException { 776 return allLineLocations(vm.getDefaultStratum(), null); 777 } 778 779 public List allLineLocations(String stratumID, String sourceName) 780 throws AbsentInformationException { 781 checkPrepared(); 782 boolean someAbsent = false; // A method that should have info, didn't 783 SDE.Stratum stratum = stratum(stratumID); 784 List list = new ArrayList(); // location list 785 786 for (Iterator iter = methods().iterator(); iter.hasNext(); ) { 787 MethodImpl method = (MethodImpl)iter.next(); 788 try { 789 list.addAll( 790 method.allLineLocations(stratum.id(), sourceName)); 791 } catch(AbsentInformationException exc) { 792 someAbsent = true; 793 } 794 } 795 796 // If we retrieved no line info, and at least one of the methods 797 // should have had some (as determined by an 798 // AbsentInformationException being thrown) then we rethrow 799 // the AbsentInformationException. 800 if (someAbsent && list.size() == 0) { 801 throw new AbsentInformationException(); 802 } 803 return list; 804 } 805 806 public List locationsOfLine(int lineNumber) 807 throws AbsentInformationException { 808 return locationsOfLine(vm.getDefaultStratum(), 809 null, 810 lineNumber); 811 } 812 813 public List locationsOfLine(String stratumID, 814 String sourceName, 815 int lineNumber) 816 throws AbsentInformationException { 817 checkPrepared(); 818 // A method that should have info, didn't 819 boolean someAbsent = false; 820 // A method that should have info, did 821 boolean somePresent = false; 822 List methods = methods(); 823 SDE.Stratum stratum = stratum(stratumID); 824 825 List list = new ArrayList(); 826 827 Iterator iter = methods.iterator(); 828 while(iter.hasNext()) { 829 MethodImpl method = (MethodImpl)iter.next(); 830 // eliminate native and abstract to eliminate 831 // false positives 832 if (!method.isAbstract() && 833 !method.isNative()) { 834 try { 835 list.addAll( 836 method.locationsOfLine(stratum.id(), 837 sourceName, 838 lineNumber)); 839 somePresent = true; 840 } catch(AbsentInformationException exc) { 841 someAbsent = true; 842 } 843 } 844 } 845 if (someAbsent && !somePresent) { 846 throw new AbsentInformationException(); 847 } 848 return list; 849 } 850 851 Klass ref() { 852 return saKlass; 853 } 854 855 856 /* 857 * Return true if an instance of this type 858 * can be assigned to a variable of the given type 859 */ 860 abstract boolean isAssignableTo(ReferenceType type); 861 862 boolean isAssignableFrom(ReferenceType type) { 863 return ((ReferenceTypeImpl)type).isAssignableTo(this); 864 } 865 866 boolean isAssignableFrom(ObjectReference object) { 867 return object == null || 868 isAssignableFrom(object.referenceType()); 869 } 870 871 int indexOf(Method method) { 872 // Make sure they're all here - the obsolete method 873 // won't be found and so will have index -1 874 return methods().indexOf(method); 875 } 876 877 int indexOf(Field field) { 878 // Make sure they're all here 879 return fields().indexOf(field); 880 } 881 882 private static boolean isPrimitiveArray(String signature) { 883 int i = signature.lastIndexOf('['); 884 /* 885 * TO DO: Centralize JNI signature knowledge. 886 * 887 * Ref: 888 * jdk1.4/doc/guide/jpda/jdi/com/sun/jdi/doc-files/signature.html 889 */ 890 boolean isPA; 891 if (i < 0) { 892 isPA = false; 893 } else { 894 char c = signature.charAt(i + 1); 895 isPA = (c != 'L'); 896 } 897 return isPA; 898 } 899 900 Type findType(String signature) throws ClassNotLoadedException { 901 Type type; 902 if (signature.length() == 1) { 903 /* OTI FIX: Must be a primitive type or the void type */ 904 char sig = signature.charAt(0); 905 if (sig == 'V') { 906 type = vm.theVoidType(); 907 } else { 908 type = vm.primitiveTypeMirror(sig); 909 } 910 } else { 911 // Must be a reference type. 912 ClassLoaderReferenceImpl loader = 913 (ClassLoaderReferenceImpl)classLoader(); 914 if ((loader == null) || 915 (isPrimitiveArray(signature)) //Work around 4450091 916 ) { 917 // Caller wants type of boot class field 918 type = vm.findBootType(signature); 919 } else { 920 // Caller wants type of non-boot class field 921 type = loader.findType(signature); 922 } 923 } 924 return type; 925 } 926 927 String loaderString() { 928 if (classLoader() != null) { 929 return "loaded by " + classLoader().toString(); 930 } else { 931 return "loaded by bootstrap loader"; 932 } 933 } 934 935 long uniqueID() { 936 return vm.getAddressValue(ref()); 937 } 938 939 // new method since 1.6 940 public int majorVersion() { 941 if (!vm.canGetClassFileVersion()) { 942 throw new UnsupportedOperationException("Cannot get class file version"); 943 } 944 return (int)((InstanceKlass)saKlass).majorVersion(); 945 } 946 947 // new method since 1.6 948 public int minorVersion() { 949 if (!vm.canGetClassFileVersion()) { 950 throw new UnsupportedOperationException("Cannot get class file version"); 951 } 952 return (int)((InstanceKlass)saKlass).minorVersion(); 953 } 954 955 // new method since 1.6 956 public int constantPoolCount() { 957 if (!vm.canGetConstantPool()) { 958 throw new UnsupportedOperationException("Cannot get constant pool"); 959 } 960 if (saKlass instanceof ArrayKlass) { 961 return 0; 962 } else { 963 return (int)((InstanceKlass)saKlass).getConstants().getLength(); 964 } 965 } 966 967 // new method since 1.6 968 public byte[] constantPool() { 969 if (!vm.canGetConstantPool()) { 970 throw new UnsupportedOperationException("Cannot get constant pool"); 971 } 972 if (this instanceof ArrayType || this instanceof PrimitiveType) { 973 byte bytes[] = new byte[0]; 974 return bytes; 975 } else { 976 ByteArrayOutputStream bs = new ByteArrayOutputStream(); 977 try { 978 ((InstanceKlass)saKlass).getConstants().writeBytes(bs); 979 } catch (IOException ex) { 980 ex.printStackTrace(); 981 byte bytes[] = new byte[0]; 982 return bytes; 983 } 984 return bs.toByteArray(); 985 } 986 } 987 }