1 /* 2 * Copyright (c) 2002, 2012, 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 ReferenceTypeImpl(VirtualMachine aVm, sun.jvm.hotspot.oops.Klass klass)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 typeNameAsSymbol()72 Symbol typeNameAsSymbol() { 73 return typeNameSymbol; 74 } 75 getMethodMirror(sun.jvm.hotspot.oops.Method ref)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 equals(Object obj)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 hashCode()122 public int hashCode() { 123 return saKlass.hashCode(); 124 } 125 compareTo(ReferenceType refType)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 Klass rf1 = ref(); 139 Klass 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.getAddress().minus(rf2.getAddress()) < 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 Method*s 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 extension = ((InstanceKlass)saKlass).getSourceDebugExtension(); 692 } 693 if (extension == null) { 694 sde = NO_SDE_INFO_MARK; 695 } else { 696 sde = new SDE(extension); 697 } 698 sdeRef = new SoftReference(sde); 699 } 700 return sde; 701 } 702 703 public List availableStrata() { 704 SDE sde = sourceDebugExtensionInfo(); 705 if (sde.isValid()) { 706 return sde.availableStrata(); 707 } else { 708 List strata = new ArrayList(); 709 strata.add(SDE.BASE_STRATUM_NAME); 710 return strata; 711 } 712 } 713 714 /** 715 * Always returns non-null stratumID 716 */ 717 public String defaultStratum() { 718 SDE sdei = sourceDebugExtensionInfo(); 719 if (sdei.isValid()) { 720 return sdei.defaultStratumId; 721 } else { 722 return SDE.BASE_STRATUM_NAME; 723 } 724 } 725 726 public final int modifiers() { 727 if (modifiers == -1) { 728 modifiers = getModifiers(); 729 } 730 return modifiers; 731 } 732 733 // new method since 1.6. 734 // Real body will be supplied later. 735 public List instances(long maxInstances) { 736 if (!vm.canGetInstanceInfo()) { 737 throw new UnsupportedOperationException( 738 "target does not support getting instances"); 739 } 740 741 if (maxInstances < 0) { 742 throw new IllegalArgumentException("maxInstances is less than zero: " 743 + maxInstances); 744 } 745 746 final List objects = new ArrayList(0); 747 if (isAbstract() || (this instanceof InterfaceType)) { 748 return objects; 749 } 750 751 final Klass givenKls = this.ref(); 752 final long max = maxInstances; 753 vm.saObjectHeap().iterate(new DefaultHeapVisitor() { 754 private long instCount=0; 755 public boolean doObj(Oop oop) { 756 if (givenKls.equals(oop.getKlass())) { 757 objects.add(vm.objectMirror(oop)); 758 instCount++; 759 } 760 if (max > 0 && instCount >= max) { 761 return true; 762 } 763 return false; 764 } 765 }); 766 return objects; 767 } 768 769 int getModifiers() { 770 return (int) saKlass.getClassModifiers(); 771 } 772 773 public List allLineLocations() 774 throws AbsentInformationException { 775 return allLineLocations(vm.getDefaultStratum(), null); 776 } 777 778 public List allLineLocations(String stratumID, String sourceName) 779 throws AbsentInformationException { 780 checkPrepared(); 781 boolean someAbsent = false; // A method that should have info, didn't 782 SDE.Stratum stratum = stratum(stratumID); 783 List list = new ArrayList(); // location list 784 785 for (Iterator iter = methods().iterator(); iter.hasNext(); ) { 786 MethodImpl method = (MethodImpl)iter.next(); 787 try { 788 list.addAll( 789 method.allLineLocations(stratum.id(), sourceName)); 790 } catch(AbsentInformationException exc) { 791 someAbsent = true; 792 } 793 } 794 795 // If we retrieved no line info, and at least one of the methods 796 // should have had some (as determined by an 797 // AbsentInformationException being thrown) then we rethrow 798 // the AbsentInformationException. 799 if (someAbsent && list.size() == 0) { 800 throw new AbsentInformationException(); 801 } 802 return list; 803 } 804 805 public List locationsOfLine(int lineNumber) 806 throws AbsentInformationException { 807 return locationsOfLine(vm.getDefaultStratum(), 808 null, 809 lineNumber); 810 } 811 812 public List locationsOfLine(String stratumID, 813 String sourceName, 814 int lineNumber) 815 throws AbsentInformationException { 816 checkPrepared(); 817 // A method that should have info, didn't 818 boolean someAbsent = false; 819 // A method that should have info, did 820 boolean somePresent = false; 821 List methods = methods(); 822 SDE.Stratum stratum = stratum(stratumID); 823 824 List list = new ArrayList(); 825 826 Iterator iter = methods.iterator(); 827 while(iter.hasNext()) { 828 MethodImpl method = (MethodImpl)iter.next(); 829 // eliminate native and abstract to eliminate 830 // false positives 831 if (!method.isAbstract() && 832 !method.isNative()) { 833 try { 834 list.addAll( 835 method.locationsOfLine(stratum.id(), 836 sourceName, 837 lineNumber)); 838 somePresent = true; 839 } catch(AbsentInformationException exc) { 840 someAbsent = true; 841 } 842 } 843 } 844 if (someAbsent && !somePresent) { 845 throw new AbsentInformationException(); 846 } 847 return list; 848 } 849 850 Klass ref() { 851 return saKlass; 852 } 853 854 855 /* 856 * Return true if an instance of this type 857 * can be assigned to a variable of the given type 858 */ 859 abstract boolean isAssignableTo(ReferenceType type); 860 861 boolean isAssignableFrom(ReferenceType type) { 862 return ((ReferenceTypeImpl)type).isAssignableTo(this); 863 } 864 865 boolean isAssignableFrom(ObjectReference object) { 866 return object == null || 867 isAssignableFrom(object.referenceType()); 868 } 869 870 int indexOf(Method method) { 871 // Make sure they're all here - the obsolete method 872 // won't be found and so will have index -1 873 return methods().indexOf(method); 874 } 875 876 int indexOf(Field field) { 877 // Make sure they're all here 878 return fields().indexOf(field); 879 } 880 881 private static boolean isPrimitiveArray(String signature) { 882 int i = signature.lastIndexOf('['); 883 /* 884 * TO DO: Centralize JNI signature knowledge. 885 * 886 * Ref: 887 * jdk1.4/doc/guide/jpda/jdi/com/sun/jdi/doc-files/signature.html 888 */ 889 boolean isPA; 890 if (i < 0) { 891 isPA = false; 892 } else { 893 char c = signature.charAt(i + 1); 894 isPA = (c != 'L'); 895 } 896 return isPA; 897 } 898 899 Type findType(String signature) throws ClassNotLoadedException { 900 Type type; 901 if (signature.length() == 1) { 902 /* OTI FIX: Must be a primitive type or the void type */ 903 char sig = signature.charAt(0); 904 if (sig == 'V') { 905 type = vm.theVoidType(); 906 } else { 907 type = vm.primitiveTypeMirror(sig); 908 } 909 } else { 910 // Must be a reference type. 911 ClassLoaderReferenceImpl loader = 912 (ClassLoaderReferenceImpl)classLoader(); 913 if ((loader == null) || 914 (isPrimitiveArray(signature)) //Work around 4450091 915 ) { 916 // Caller wants type of boot class field 917 type = vm.findBootType(signature); 918 } else { 919 // Caller wants type of non-boot class field 920 type = loader.findType(signature); 921 } 922 } 923 return type; 924 } 925 926 String loaderString() { 927 if (classLoader() != null) { 928 return "loaded by " + classLoader().toString(); 929 } else { 930 return "loaded by bootstrap loader"; 931 } 932 } 933 934 long uniqueID() { 935 return vm.getAddressValue(ref().getJavaMirror()); 936 } 937 938 // new method since 1.6 939 public int majorVersion() { 940 if (!vm.canGetClassFileVersion()) { 941 throw new UnsupportedOperationException("Cannot get class file version"); 942 } 943 return (int)((InstanceKlass)saKlass).majorVersion(); 944 } 945 946 // new method since 1.6 947 public int minorVersion() { 948 if (!vm.canGetClassFileVersion()) { 949 throw new UnsupportedOperationException("Cannot get class file version"); 950 } 951 return (int)((InstanceKlass)saKlass).minorVersion(); 952 } 953 954 // new method since 1.6 955 public int constantPoolCount() { 956 if (!vm.canGetConstantPool()) { 957 throw new UnsupportedOperationException("Cannot get constant pool"); 958 } 959 if (saKlass instanceof ArrayKlass) { 960 return 0; 961 } else { 962 return (int)((InstanceKlass)saKlass).getConstants().getLength(); 963 } 964 } 965 966 // new method since 1.6 967 public byte[] constantPool() { 968 if (!vm.canGetConstantPool()) { 969 throw new UnsupportedOperationException("Cannot get constant pool"); 970 } 971 if (this instanceof ArrayType || this instanceof PrimitiveType) { 972 byte bytes[] = new byte[0]; 973 return bytes; 974 } else { 975 ByteArrayOutputStream bs = new ByteArrayOutputStream(); 976 try { 977 ((InstanceKlass)saKlass).getConstants().writeBytes(bs); 978 } catch (IOException ex) { 979 ex.printStackTrace(); 980 byte bytes[] = new byte[0]; 981 return bytes; 982 } 983 return bs.toByteArray(); 984 } 985 } 986 } 987