1 /* 2 * Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 20 * CA 95054 USA or visit www.sun.com if you need additional information or 21 * have any questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.jdi; 26 27 import com.sun.jdi.*; 28 import com.sun.jdi.event.EventQueue; 29 import com.sun.jdi.request.EventRequestManager; 30 31 import sun.jvm.hotspot.HotSpotAgent; 32 import sun.jvm.hotspot.types.TypeDataBase; 33 import sun.jvm.hotspot.oops.Klass; 34 import sun.jvm.hotspot.oops.InstanceKlass; 35 import sun.jvm.hotspot.oops.ArrayKlass; 36 import sun.jvm.hotspot.oops.ObjArrayKlass; 37 import sun.jvm.hotspot.oops.TypeArrayKlass; 38 import sun.jvm.hotspot.oops.Oop; 39 import sun.jvm.hotspot.oops.Instance; 40 import sun.jvm.hotspot.oops.Array; 41 import sun.jvm.hotspot.oops.ObjArray; 42 import sun.jvm.hotspot.oops.TypeArray; 43 import sun.jvm.hotspot.oops.Symbol; 44 import sun.jvm.hotspot.oops.ObjectHeap; 45 import sun.jvm.hotspot.oops.DefaultHeapVisitor; 46 import sun.jvm.hotspot.oops.JVMDIClassStatus; 47 import sun.jvm.hotspot.runtime.VM; 48 import sun.jvm.hotspot.runtime.JavaThread; 49 import sun.jvm.hotspot.memory.SystemDictionary; 50 import sun.jvm.hotspot.memory.SymbolTable; 51 import sun.jvm.hotspot.memory.Universe; 52 import sun.jvm.hotspot.utilities.Assert; 53 54 import java.util.List; 55 import java.util.ArrayList; 56 import java.util.Map; 57 import java.util.Iterator; 58 import java.util.Collections; 59 import java.util.HashMap; 60 import java.util.Observer; 61 import java.util.StringTokenizer; 62 import java.lang.ref.SoftReference; 63 import java.lang.ref.ReferenceQueue; 64 import java.lang.ref.Reference; 65 66 public class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtualMachine { 67 68 private HotSpotAgent saAgent = new HotSpotAgent(); 69 private VM saVM; 70 private Universe saUniverse; 71 private SystemDictionary saSystemDictionary; 72 private SymbolTable saSymbolTable; 73 private ObjectHeap saObjectHeap; 74 75 VM saVM() { 76 return saVM; 77 } 78 79 SystemDictionary saSystemDictionary() { 80 return saSystemDictionary; 81 } 82 83 SymbolTable saSymbolTable() { 84 return saSymbolTable; 85 } 86 87 Universe saUniverse() { 88 return saUniverse; 89 } 90 91 ObjectHeap saObjectHeap() { 92 return saObjectHeap; 93 } 94 95 com.sun.jdi.VirtualMachineManager vmmgr; 96 97 private final ThreadGroup threadGroupForJDI; 98 99 // Per-vm singletons for primitive types and for void. 100 // singleton-ness protected by "synchronized(this)". 101 private BooleanType theBooleanType; 102 private ByteType theByteType; 103 private CharType theCharType; 104 private ShortType theShortType; 105 private IntegerType theIntegerType; 106 private LongType theLongType; 107 private FloatType theFloatType; 108 private DoubleType theDoubleType; 109 110 private VoidType theVoidType; 111 112 private VoidValue voidVal; 113 private Map typesByID; // Map<Klass, ReferenceTypeImpl> 114 private List typesBySignature; // List<ReferenceTypeImpl> - used in signature search 115 private boolean retrievedAllTypes = false; 116 private List bootstrapClasses; // all bootstrap classes 117 private ArrayList allThreads; 118 private ArrayList topLevelGroups; 119 final int sequenceNumber; 120 121 // ObjectReference cache 122 // "objectsByID" protected by "synchronized(this)". 123 private final Map objectsByID = new HashMap(); 124 private final ReferenceQueue referenceQueue = new ReferenceQueue(); 125 126 // names of some well-known classes to jdi 127 private Symbol javaLangString; 128 private Symbol javaLangThread; 129 private Symbol javaLangThreadGroup; 130 private Symbol javaLangClass; 131 private Symbol javaLangClassLoader; 132 133 // used in ReferenceTypeImpl.isThrowableBacktraceField 134 private Symbol javaLangThrowable; 135 136 // names of classes used in array assignment check 137 // refer to ArrayTypeImpl.isAssignableTo 138 private Symbol javaLangObject; 139 private Symbol javaLangCloneable; 140 private Symbol javaIoSerializable; 141 142 // symbol used in ClassTypeImpl.isEnum check 143 private Symbol javaLangEnum; 144 145 Symbol javaLangObject() { 146 return javaLangObject; 147 } 148 149 Symbol javaLangCloneable() { 150 return javaLangCloneable; 151 } 152 153 Symbol javaIoSerializable() { 154 return javaIoSerializable; 155 } 156 157 Symbol javaLangEnum() { 158 return javaLangEnum; 159 } 160 161 Symbol javaLangThrowable() { 162 return javaLangThrowable; 163 } 164 165 // name of the current default stratum 166 private String defaultStratum; 167 168 // initialize known class name symbols 169 private void initClassNameSymbols() { 170 SymbolTable st = saSymbolTable(); 171 javaLangString = st.probe("java/lang/String"); 172 javaLangThread = st.probe("java/lang/Thread"); 173 javaLangThreadGroup = st.probe("java/lang/ThreadGroup"); 174 javaLangClass = st.probe("java/lang/Class"); 175 javaLangClassLoader = st.probe("java/lang/ClassLoader"); 176 javaLangThrowable = st.probe("java/lang/Throwable"); 177 javaLangObject = st.probe("java/lang/Object"); 178 javaLangCloneable = st.probe("java/lang/Cloneable"); 179 javaIoSerializable = st.probe("java/io/Serializable"); 180 javaLangEnum = st.probe("java/lang/Enum"); 181 } 182 183 private void init() { 184 saVM = VM.getVM(); 185 saUniverse = saVM.getUniverse(); 186 saSystemDictionary = saVM.getSystemDictionary(); 187 saSymbolTable = saVM.getSymbolTable(); 188 saObjectHeap = saVM.getObjectHeap(); 189 initClassNameSymbols(); 190 } 191 192 static public VirtualMachineImpl createVirtualMachineForCorefile(VirtualMachineManager mgr, 193 String javaExecutableName, 194 String coreFileName, 195 int sequenceNumber) 196 throws Exception { 197 if (Assert.ASSERTS_ENABLED) { 198 Assert.that(coreFileName != null, "SA VirtualMachineImpl: core filename = null is not yet implemented"); 199 } 200 if (Assert.ASSERTS_ENABLED) { 201 Assert.that(javaExecutableName != null, "SA VirtualMachineImpl: java executable = null is not yet implemented"); 202 } 203 204 VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber); 205 try { 206 myvm.saAgent.attach(javaExecutableName, coreFileName); 207 myvm.init(); 208 } catch (Exception ee) { 209 myvm.saAgent.detach(); 210 throw ee; 211 } 212 return myvm; 213 } 214 215 static public VirtualMachineImpl createVirtualMachineForPID(VirtualMachineManager mgr, 216 int pid, 217 int sequenceNumber) 218 throws Exception { 219 220 VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber); 221 try { 222 myvm.saAgent.attach(pid); 223 myvm.init(); 224 } catch (Exception ee) { 225 myvm.saAgent.detach(); 226 throw ee; 227 } 228 return myvm; 229 } 230 231 static public VirtualMachineImpl createVirtualMachineForServer(VirtualMachineManager mgr, 232 String server, 233 int sequenceNumber) 234 throws Exception { 235 if (Assert.ASSERTS_ENABLED) { 236 Assert.that(server != null, "SA VirtualMachineImpl: DebugServer = null is not yet implemented"); 237 } 238 239 VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber); 240 try { 241 myvm.saAgent.attach(server); 242 myvm.init(); 243 } catch (Exception ee) { 244 myvm.saAgent.detach(); 245 throw ee; 246 } 247 return myvm; 248 } 249 250 251 VirtualMachineImpl(VirtualMachineManager mgr, int sequenceNumber) 252 throws Exception { 253 super(null); // Can't use super(this) 254 vm = this; 255 256 this.sequenceNumber = sequenceNumber; 257 this.vmmgr = mgr; 258 259 /* Create ThreadGroup to be used by all threads servicing 260 * this VM. 261 */ 262 threadGroupForJDI = new ThreadGroup("JDI [" + 263 this.hashCode() + "]"); 264 265 ((com.sun.tools.jdi.VirtualMachineManagerImpl)mgr).addVirtualMachine(this); 266 267 // By default SA agent classes prefer Windows process debugger 268 // to windbg debugger. SA expects special properties to be set 269 // to choose other debuggers. We will set those here before 270 // attaching to SA agent. 271 272 System.setProperty("sun.jvm.hotspot.debugger.useWindbgDebugger", "true"); 273 } 274 275 // we reflectively use newly spec'ed class because our ALT_BOOTDIR 276 // is 1.4.2 and not 1.5. 277 private static Class vmCannotBeModifiedExceptionClass = null; 278 void throwNotReadOnlyException(String operation) { 279 RuntimeException re = null; 280 if (vmCannotBeModifiedExceptionClass == null) { 281 try { 282 vmCannotBeModifiedExceptionClass = Class.forName("com.sun.jdi.VMCannotBeModifiedException"); 283 } catch (ClassNotFoundException cnfe) { 284 vmCannotBeModifiedExceptionClass = UnsupportedOperationException.class; 285 } 286 } 287 try { 288 re = (RuntimeException) vmCannotBeModifiedExceptionClass.newInstance(); 289 } catch (Exception exp) { 290 re = new RuntimeException(exp.getMessage()); 291 } 292 throw re; 293 } 294 295 public boolean equals(Object obj) { 296 // Oh boy; big recursion troubles if we don't have this! 297 // See MirrorImpl.equals 298 return this == obj; 299 } 300 301 public int hashCode() { 302 // big recursion if we don't have this. See MirrorImpl.hashCode 303 return System.identityHashCode(this); 304 } 305 306 public List classesByName(String className) { 307 String signature = JNITypeParser.typeNameToSignature(className); 308 List list; 309 if (!retrievedAllTypes) { 310 retrieveAllClasses(); 311 } 312 list = findReferenceTypes(signature); 313 return Collections.unmodifiableList(list); 314 } 315 316 public List allClasses() { 317 if (!retrievedAllTypes) { 318 retrieveAllClasses(); 319 } 320 ArrayList a; 321 synchronized (this) { 322 a = new ArrayList(typesBySignature); 323 } 324 return Collections.unmodifiableList(a); 325 } 326 327 // classes loaded by bootstrap loader 328 List bootstrapClasses() { 329 if (bootstrapClasses == null) { 330 bootstrapClasses = new ArrayList(); 331 List all = allClasses(); 332 for (Iterator itr = all.iterator(); itr.hasNext();) { 333 ReferenceType type = (ReferenceType) itr.next(); 334 if (type.classLoader() == null) { 335 bootstrapClasses.add(type); 336 } 337 } 338 } 339 return bootstrapClasses; 340 } 341 342 private synchronized List findReferenceTypes(String signature) { 343 if (typesByID == null) { 344 return new ArrayList(0); 345 } 346 347 // we haven't sorted types by signatures. But we can take 348 // advantage of comparing symbols instead of name. In the worst 349 // case, we will be comparing N addresses rather than N strings 350 // where N being total no. of classes in allClasses() list. 351 352 // The signature could be Lx/y/z; or [.... 353 // If it is Lx/y/z; the internal type name is x/y/x 354 // for array klasses internal type name is same as 355 // signature 356 String typeName = null; 357 if (signature.charAt(0) == 'L') { 358 typeName = signature.substring(1, signature.length() - 1); 359 } else { 360 typeName = signature; 361 } 362 363 Symbol typeNameSym = saSymbolTable().probe(typeName); 364 // if there is no symbol in VM, then we wouldn't have that type 365 if (typeNameSym == null) { 366 return new ArrayList(0); 367 } 368 369 Iterator iter = typesBySignature.iterator(); 370 List list = new ArrayList(); 371 while (iter.hasNext()) { 372 // We have cached type name as symbol in reference type 373 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); 374 if (typeNameSym.equals(type.typeNameAsSymbol())) { 375 list.add(type); 376 } 377 } 378 return list; 379 } 380 381 private void retrieveAllClasses() { 382 final List saKlasses = new ArrayList(); 383 SystemDictionary.ClassVisitor visitor = new SystemDictionary.ClassVisitor() { 384 public void visit(Klass k) { 385 for (Klass l = k; l != null; l = l.arrayKlassOrNull()) { 386 // for non-array classes filter out un-prepared classes 387 // refer to 'allClasses' in share/back/VirtualMachineImpl.c 388 if (l instanceof ArrayKlass) { 389 saKlasses.add(l); 390 } else { 391 int status = l.getClassStatus(); 392 if ((status & JVMDIClassStatus.PREPARED) != 0) { 393 saKlasses.add(l); 394 } 395 } 396 } 397 } 398 }; 399 400 // refer to jvmtiGetLoadedClasses.cpp - getLoadedClasses in VM code. 401 402 // classes from SystemDictionary 403 saSystemDictionary.classesDo(visitor); 404 405 // From SystemDictionary we do not get primitive single 406 // dimensional array classes. add primitive single dimensional array 407 // klasses from Universe. 408 saVM.getUniverse().basicTypeClassesDo(visitor); 409 410 // Hold lock during processing to improve performance 411 // and to have safe check/set of retrievedAllTypes 412 synchronized (this) { 413 if (!retrievedAllTypes) { 414 // Number of classes 415 int count = saKlasses.size(); 416 for (int ii = 0; ii < count; ii++) { 417 Klass kk = (Klass)saKlasses.get(ii); 418 ReferenceTypeImpl type = referenceType(kk); 419 } 420 retrievedAllTypes = true; 421 } 422 } 423 } 424 425 ReferenceTypeImpl referenceType(Klass kk) { 426 ReferenceTypeImpl retType = null; 427 synchronized (this) { 428 if (typesByID != null) { 429 retType = (ReferenceTypeImpl)typesByID.get(kk); 430 } 431 if (retType == null) { 432 retType = addReferenceType(kk); 433 } 434 } 435 return retType; 436 } 437 438 private void initReferenceTypes() { 439 typesByID = new HashMap(); 440 typesBySignature = new ArrayList(); 441 } 442 443 private synchronized ReferenceTypeImpl addReferenceType(Klass kk) { 444 if (typesByID == null) { 445 initReferenceTypes(); 446 } 447 ReferenceTypeImpl newRefType = null; 448 if (kk instanceof ObjArrayKlass || kk instanceof TypeArrayKlass) { 449 newRefType = new ArrayTypeImpl(this, (ArrayKlass)kk); 450 } else if (kk instanceof InstanceKlass) { 451 if (kk.isInterface()) { 452 newRefType = new InterfaceTypeImpl(this, (InstanceKlass)kk); 453 } else { 454 newRefType = new ClassTypeImpl(this, (InstanceKlass)kk); 455 } 456 } else { 457 throw new RuntimeException("should not reach here"); 458 } 459 460 typesByID.put(kk, newRefType); 461 typesBySignature.add(newRefType); 462 return newRefType; 463 } 464 465 ThreadGroup threadGroupForJDI() { 466 return threadGroupForJDI; 467 } 468 469 public void redefineClasses(Map classToBytes) { 470 throwNotReadOnlyException("VirtualMachineImpl.redefineClasses()"); 471 } 472 473 private List getAllThreads() { 474 if (allThreads == null) { 475 allThreads = new ArrayList(10); // Might be enough, might not be 476 for (sun.jvm.hotspot.runtime.JavaThread thread = 477 saVM.getThreads().first(); thread != null; 478 thread = thread.next()) { 479 // refer to JvmtiEnv::GetAllThreads in jvmtiEnv.cpp. 480 // filter out the hidden-from-external-view threads. 481 if (thread.isHiddenFromExternalView() == false) { 482 ThreadReferenceImpl myThread = threadMirror(thread); 483 allThreads.add(myThread); 484 } 485 } 486 } 487 return allThreads; 488 } 489 490 public List allThreads() { //fixme jjh 491 return Collections.unmodifiableList(getAllThreads()); 492 } 493 494 public void suspend() { 495 throwNotReadOnlyException("VirtualMachineImpl.suspend()"); 496 } 497 498 public void resume() { 499 throwNotReadOnlyException("VirtualMachineImpl.resume()"); 500 } 501 502 public List topLevelThreadGroups() { //fixme jjh 503 // The doc for ThreadGroup says that The top-level thread group 504 // is the only thread group whose parent is null. This means there is 505 // only one top level thread group. There will be a thread in this 506 // group so we will just find a thread whose threadgroup has no parent 507 // and that will be it. 508 509 if (topLevelGroups == null) { 510 topLevelGroups = new ArrayList(1); 511 Iterator myIt = getAllThreads().iterator(); 512 while (myIt.hasNext()) { 513 ThreadReferenceImpl myThread = (ThreadReferenceImpl)myIt.next(); 514 ThreadGroupReference myGroup = myThread.threadGroup(); 515 ThreadGroupReference myParent = myGroup.parent(); 516 if (myGroup.parent() == null) { 517 topLevelGroups.add(myGroup); 518 break; 519 } 520 } 521 } 522 return Collections.unmodifiableList(topLevelGroups); 523 } 524 525 public EventQueue eventQueue() { 526 throwNotReadOnlyException("VirtualMachine.eventQueue()"); 527 return null; 528 } 529 530 public EventRequestManager eventRequestManager() { 531 throwNotReadOnlyException("VirtualMachineImpl.eventRequestManager()"); 532 return null; 533 } 534 535 public BooleanValue mirrorOf(boolean value) { 536 return new BooleanValueImpl(this,value); 537 } 538 539 public ByteValue mirrorOf(byte value) { 540 return new ByteValueImpl(this,value); 541 } 542 543 public CharValue mirrorOf(char value) { 544 return new CharValueImpl(this,value); 545 } 546 547 public ShortValue mirrorOf(short value) { 548 return new ShortValueImpl(this,value); 549 } 550 551 public IntegerValue mirrorOf(int value) { 552 return new IntegerValueImpl(this,value); 553 } 554 555 public LongValue mirrorOf(long value) { 556 return new LongValueImpl(this,value); 557 } 558 559 public FloatValue mirrorOf(float value) { 560 return new FloatValueImpl(this,value); 561 } 562 563 public DoubleValue mirrorOf(double value) { 564 return new DoubleValueImpl(this,value); 565 } 566 567 public StringReference mirrorOf(String value) { 568 throwNotReadOnlyException("VirtualMachinestop.mirrorOf(String)"); 569 return null; 570 } 571 572 public VoidValue mirrorOfVoid() { 573 if (voidVal == null) { 574 voidVal = new VoidValueImpl(this); 575 } 576 return voidVal; 577 } 578 579 580 public Process process() { 581 throwNotReadOnlyException("VirtualMachine.process"); 582 return null; 583 } 584 585 // dispose observer for Class re-use. refer to ConnectorImpl. 586 private Observer disposeObserver; 587 588 // ConnectorImpl loaded by a different class loader can not access it. 589 // i.e., runtime package of <ConnectorImpl, L1> is not the same that of 590 // <VirtualMachineImpl, L2> when L1 != L2. So, package private method 591 // can be called reflectively after using setAccessible(true). 592 593 void setDisposeObserver(Observer observer) { 594 disposeObserver = observer; 595 } 596 597 private void notifyDispose() { 598 if (Assert.ASSERTS_ENABLED) { 599 Assert.that(disposeObserver != null, "null VM.dispose observer"); 600 } 601 disposeObserver.update(null, null); 602 } 603 604 public void dispose() { 605 saAgent.detach(); 606 notifyDispose(); 607 } 608 609 public void exit(int exitCode) { 610 throwNotReadOnlyException("VirtualMachine.exit(int)"); 611 } 612 613 public boolean canBeModified() { 614 return false; 615 } 616 617 public boolean canWatchFieldModification() { 618 return false; 619 } 620 621 public boolean canWatchFieldAccess() { 622 return false; 623 } 624 625 public boolean canGetBytecodes() { 626 return true; 627 } 628 629 public boolean canGetSyntheticAttribute() { 630 return true; 631 } 632 633 // FIXME: For now, all monitor capabilities are disabled 634 public boolean canGetOwnedMonitorInfo() { 635 return false; 636 } 637 638 public boolean canGetCurrentContendedMonitor() { 639 return false; 640 } 641 642 public boolean canGetMonitorInfo() { 643 return false; 644 } 645 646 // because this SA works only with 1.5 and update releases 647 // this should always succeed unlike JVMDI/JDI. 648 public boolean canGet1_5LanguageFeatures() { 649 return true; 650 } 651 652 public boolean canUseInstanceFilters() { 653 return false; 654 } 655 656 public boolean canRedefineClasses() { 657 return false; 658 } 659 660 public boolean canAddMethod() { 661 return false; 662 } 663 664 public boolean canUnrestrictedlyRedefineClasses() { 665 return false; 666 } 667 668 public boolean canPopFrames() { 669 return false; 670 } 671 672 public boolean canGetSourceDebugExtension() { 673 // We can use InstanceKlass.getSourceDebugExtension only if 674 // ClassFileParser parsed the info. But, ClassFileParser parses 675 // SourceDebugExtension attribute only if corresponding JVMDI/TI 676 // capability is set to true. Currently, vmStructs does not expose 677 // JVMDI/TI capabilities and hence we conservatively assume false. 678 return false; 679 } 680 681 public boolean canRequestVMDeathEvent() { 682 return false; 683 } 684 685 // new method since 1.6 686 public boolean canForceEarlyReturn() { 687 return false; 688 } 689 690 // new method since 1.6 691 public boolean canGetConstantPool() { 692 return true; 693 } 694 695 // new method since 1.6 696 public boolean canGetClassFileVersion() { 697 return true; 698 } 699 700 // new method since 1.6. 701 public boolean canGetMethodReturnValues() { 702 return false; 703 } 704 705 // new method since 1.6 706 // Real body will be supplied later. 707 public boolean canGetInstanceInfo() { 708 return true; 709 } 710 711 // new method since 1.6 712 public boolean canUseSourceNameFilters() { 713 return false; 714 } 715 716 // new method since 1.6. 717 public boolean canRequestMonitorEvents() { 718 return false; 719 } 720 721 // new method since 1.6. 722 public boolean canGetMonitorFrameInfo() { 723 return true; 724 } 725 726 // new method since 1.6 727 // Real body will be supplied later. 728 public long[] instanceCounts(List classes) { 729 if (!canGetInstanceInfo()) { 730 throw new UnsupportedOperationException( 731 "target does not support getting instances"); 732 } 733 734 final long[] retValue = new long[classes.size()] ; 735 736 final Klass [] klassArray = new Klass[classes.size()]; 737 738 boolean allAbstractClasses = true; 739 for (int i=0; i < classes.size(); i++) { 740 ReferenceTypeImpl rti = (ReferenceTypeImpl)classes.get(i); 741 klassArray[i] = rti.ref(); 742 retValue[i]=0; 743 if (!(rti.isAbstract() || ((ReferenceType)rti instanceof InterfaceType))) { 744 allAbstractClasses = false; 745 } 746 } 747 748 if (allAbstractClasses) { 749 return retValue; 750 } 751 final int size = classes.size(); 752 saObjectHeap.iterate(new DefaultHeapVisitor() { 753 public boolean doObj(Oop oop) { 754 for (int i=0; i < size; i++) { 755 if (klassArray[i].equals(oop.getKlass())) { 756 retValue[i]++; 757 break; 758 } 759 } 760 return false; 761 } 762 }); 763 764 return retValue; 765 } 766 767 private List getPath (String pathName) { 768 String cp = saVM.getSystemProperty(pathName); 769 String pathSep = saVM.getSystemProperty("path.separator"); 770 ArrayList al = new ArrayList(); 771 StringTokenizer st = new StringTokenizer(cp, pathSep); 772 while (st.hasMoreTokens()) { 773 al.add(st.nextToken()); 774 } 775 al.trimToSize(); 776 return al; 777 } 778 779 public List classPath() { 780 return getPath("java.class.path"); 781 } 782 783 public List bootClassPath() { 784 return getPath("sun.boot.class.path"); 785 } 786 787 public String baseDirectory() { 788 return saVM.getSystemProperty("user.dir"); 789 } 790 791 public void setDefaultStratum(String stratum) { 792 defaultStratum = stratum; 793 } 794 795 public String getDefaultStratum() { 796 return defaultStratum; 797 } 798 799 public String description() { 800 String[] versionParts = {"" + vmmgr.majorInterfaceVersion(), 801 "" + vmmgr.minorInterfaceVersion(), 802 name()}; 803 return java.text.MessageFormat.format(java.util.ResourceBundle. 804 getBundle("com.sun.tools.jdi.resources.jdi").getString("version_format"), 805 versionParts); 806 } 807 808 public String version() { 809 return saVM.getSystemProperty("java.version"); 810 } 811 812 public String name() { 813 StringBuffer sb = new StringBuffer(); 814 sb.append("JVM version "); 815 sb.append(version()); 816 sb.append(" ("); 817 sb.append(saVM.getSystemProperty("java.vm.name")); 818 sb.append(", "); 819 sb.append(saVM.getSystemProperty("java.vm.info")); 820 sb.append(")"); 821 return sb.toString(); 822 } 823 824 // from interface Mirror 825 public VirtualMachine virtualMachine() { 826 return this; 827 } 828 829 public String toString() { 830 return name(); 831 } 832 833 public void setDebugTraceMode(int traceFlags) { 834 // spec. says output is implementation dependent 835 // and trace mode may be ignored. we ignore it :-) 836 } 837 838 // heap walking API 839 840 // capability check 841 public boolean canWalkHeap() { 842 return true; 843 } 844 845 // return a list of all objects in heap 846 public List/*<ObjectReference>*/ allObjects() { 847 final List objects = new ArrayList(0); 848 saObjectHeap.iterate( 849 new DefaultHeapVisitor() { 850 public boolean doObj(Oop oop) { 851 objects.add(objectMirror(oop)); 852 return false; 853 } 854 }); 855 return objects; 856 } 857 858 // equivalent to objectsByType(type, true) 859 public List/*<ObjectReference>*/ objectsByType(ReferenceType type) { 860 return objectsByType(type, true); 861 } 862 863 // returns objects of type exactly equal to given type 864 private List/*<ObjectReference>*/ objectsByExactType(ReferenceType type) { 865 final List objects = new ArrayList(0); 866 final Klass givenKls = ((ReferenceTypeImpl)type).ref(); 867 saObjectHeap.iterate(new DefaultHeapVisitor() { 868 public boolean doObj(Oop oop) { 869 if (givenKls.equals(oop.getKlass())) { 870 objects.add(objectMirror(oop)); 871 } 872 return false; 873 } 874 }); 875 return objects; 876 } 877 878 // returns objects of given type as well as it's subtypes 879 private List/*<ObjectReference>*/ objectsBySubType(ReferenceType type) { 880 final List objects = new ArrayList(0); 881 final ReferenceType givenType = type; 882 saObjectHeap.iterate(new DefaultHeapVisitor() { 883 public boolean doObj(Oop oop) { 884 ReferenceTypeImpl curType = (ReferenceTypeImpl) referenceType(oop.getKlass()); 885 if (curType.isAssignableTo(givenType)) { 886 objects.add(objectMirror(oop)); 887 } 888 return false; 889 } 890 }); 891 return objects; 892 } 893 894 // includeSubtypes - do you want to include subclass/subtype instances of given 895 // ReferenceType or do we want objects of exact type only? 896 public List/*<ObjectReference>*/ objectsByType(ReferenceType type, boolean includeSubtypes) { 897 Klass kls = ((ReferenceTypeImpl)type).ref(); 898 if (kls instanceof InstanceKlass) { 899 InstanceKlass ik = (InstanceKlass) kls; 900 if (ik.isInterface()) { 901 if (ik.nofImplementors() == 0L) { 902 return new ArrayList(0); 903 } 904 } else { 905 // if the Klass is final or if there are no subklasses loaded yet 906 if (ik.getAccessFlagsObj().isFinal() || ik.getSubklassKlass() == null) { 907 includeSubtypes = false; 908 } 909 } 910 } else { 911 // no subtypes for primitive array types 912 ArrayTypeImpl arrayType = (ArrayTypeImpl) type; 913 try { 914 Type componentType = arrayType.componentType(); 915 if (componentType instanceof PrimitiveType) { 916 includeSubtypes = false; 917 } 918 } catch (ClassNotLoadedException cnle) { 919 // ignore. component type not yet loaded 920 } 921 } 922 923 if (includeSubtypes) { 924 return objectsBySubType(type); 925 } else { 926 return objectsByExactType(type); 927 } 928 } 929 930 Type findBootType(String signature) throws ClassNotLoadedException { 931 List types = allClasses(); 932 Iterator iter = types.iterator(); 933 while (iter.hasNext()) { 934 ReferenceType type = (ReferenceType)iter.next(); 935 if ((type.classLoader() == null) && 936 (type.signature().equals(signature))) { 937 return type; 938 } 939 } 940 JNITypeParser parser = new JNITypeParser(signature); 941 throw new ClassNotLoadedException(parser.typeName(), 942 "Type " + parser.typeName() + " not loaded"); 943 } 944 945 BooleanType theBooleanType() { 946 if (theBooleanType == null) { 947 synchronized(this) { 948 if (theBooleanType == null) { 949 theBooleanType = new BooleanTypeImpl(this); 950 } 951 } 952 } 953 return theBooleanType; 954 } 955 956 ByteType theByteType() { 957 if (theByteType == null) { 958 synchronized(this) { 959 if (theByteType == null) { 960 theByteType = new ByteTypeImpl(this); 961 } 962 } 963 } 964 return theByteType; 965 } 966 967 CharType theCharType() { 968 if (theCharType == null) { 969 synchronized(this) { 970 if (theCharType == null) { 971 theCharType = new CharTypeImpl(this); 972 } 973 } 974 } 975 return theCharType; 976 } 977 978 ShortType theShortType() { 979 if (theShortType == null) { 980 synchronized(this) { 981 if (theShortType == null) { 982 theShortType = new ShortTypeImpl(this); 983 } 984 } 985 } 986 return theShortType; 987 } 988 989 IntegerType theIntegerType() { 990 if (theIntegerType == null) { 991 synchronized(this) { 992 if (theIntegerType == null) { 993 theIntegerType = new IntegerTypeImpl(this); 994 } 995 } 996 } 997 return theIntegerType; 998 } 999 1000 LongType theLongType() { 1001 if (theLongType == null) { 1002 synchronized(this) { 1003 if (theLongType == null) { 1004 theLongType = new LongTypeImpl(this); 1005 } 1006 } 1007 } 1008 return theLongType; 1009 } 1010 1011 FloatType theFloatType() { 1012 if (theFloatType == null) { 1013 synchronized(this) { 1014 if (theFloatType == null) { 1015 theFloatType = new FloatTypeImpl(this); 1016 } 1017 } 1018 } 1019 return theFloatType; 1020 } 1021 1022 DoubleType theDoubleType() { 1023 if (theDoubleType == null) { 1024 synchronized(this) { 1025 if (theDoubleType == null) { 1026 theDoubleType = new DoubleTypeImpl(this); 1027 } 1028 } 1029 } 1030 return theDoubleType; 1031 } 1032 1033 VoidType theVoidType() { 1034 if (theVoidType == null) { 1035 synchronized(this) { 1036 if (theVoidType == null) { 1037 theVoidType = new VoidTypeImpl(this); 1038 } 1039 } 1040 } 1041 return theVoidType; 1042 } 1043 1044 PrimitiveType primitiveTypeMirror(char tag) { 1045 switch (tag) { 1046 case 'Z': 1047 return theBooleanType(); 1048 case 'B': 1049 return theByteType(); 1050 case 'C': 1051 return theCharType(); 1052 case 'S': 1053 return theShortType(); 1054 case 'I': 1055 return theIntegerType(); 1056 case 'J': 1057 return theLongType(); 1058 case 'F': 1059 return theFloatType(); 1060 case 'D': 1061 return theDoubleType(); 1062 default: 1063 throw new IllegalArgumentException("Unrecognized primitive tag " + tag); 1064 } 1065 } 1066 1067 private void processQueue() { 1068 Reference ref; 1069 while ((ref = referenceQueue.poll()) != null) { 1070 SoftObjectReference softRef = (SoftObjectReference)ref; 1071 removeObjectMirror(softRef); 1072 } 1073 } 1074 1075 // Address value is used as uniqueID by ObjectReferenceImpl 1076 long getAddressValue(Oop obj) { 1077 return vm.saVM.getDebugger().getAddressValue(obj.getHandle()); 1078 } 1079 1080 synchronized ObjectReferenceImpl objectMirror(Oop key) { 1081 1082 // Handle any queue elements that are not strongly reachable 1083 processQueue(); 1084 1085 if (key == null) { 1086 return null; 1087 } 1088 ObjectReferenceImpl object = null; 1089 1090 /* 1091 * Attempt to retrieve an existing object object reference 1092 */ 1093 SoftObjectReference ref = (SoftObjectReference)objectsByID.get(key); 1094 if (ref != null) { 1095 object = ref.object(); 1096 } 1097 1098 /* 1099 * If the object wasn't in the table, or it's soft reference was 1100 * cleared, create a new instance. 1101 */ 1102 if (object == null) { 1103 if (key instanceof Instance) { 1104 // look for well-known classes 1105 Symbol className = key.getKlass().getName(); 1106 if (Assert.ASSERTS_ENABLED) { 1107 Assert.that(className != null, "Null class name"); 1108 } 1109 Instance inst = (Instance) key; 1110 if (className.equals(javaLangString)) { 1111 object = new StringReferenceImpl(this, inst); 1112 } else if (className.equals(javaLangThread)) { 1113 object = new ThreadReferenceImpl(this, inst); 1114 } else if (className.equals(javaLangThreadGroup)) { 1115 object = new ThreadGroupReferenceImpl(this, inst); 1116 } else if (className.equals(javaLangClass)) { 1117 object = new ClassObjectReferenceImpl(this, inst); 1118 } else if (className.equals(javaLangClassLoader)) { 1119 object = new ClassLoaderReferenceImpl(this, inst); 1120 } else { 1121 // not a well-known class. But the base class may be 1122 // one of the known classes. 1123 Klass kls = key.getKlass().getSuper(); 1124 while (kls != null) { 1125 className = kls.getName(); 1126 // java.lang.Class and java.lang.String are final classes 1127 if (className.equals(javaLangThread)) { 1128 object = new ThreadReferenceImpl(this, inst); 1129 break; 1130 } else if(className.equals(javaLangThreadGroup)) { 1131 object = new ThreadGroupReferenceImpl(this, inst); 1132 break; 1133 } else if (className.equals(javaLangClassLoader)) { 1134 object = new ClassLoaderReferenceImpl(this, inst); 1135 break; 1136 } 1137 kls = kls.getSuper(); 1138 } 1139 1140 if (object == null) { 1141 // create generic object reference 1142 object = new ObjectReferenceImpl(this, inst); 1143 } 1144 } 1145 } else if (key instanceof TypeArray) { 1146 object = new ArrayReferenceImpl(this, (Array) key); 1147 } else if (key instanceof ObjArray) { 1148 object = new ArrayReferenceImpl(this, (Array) key); 1149 } else { 1150 throw new RuntimeException("unexpected object type " + key); 1151 } 1152 ref = new SoftObjectReference(key, object, referenceQueue); 1153 1154 /* 1155 * If there was no previous entry in the table, we add one here 1156 * If the previous entry was cleared, we replace it here. 1157 */ 1158 objectsByID.put(key, ref); 1159 } else { 1160 ref.incrementCount(); 1161 } 1162 1163 return object; 1164 } 1165 1166 synchronized void removeObjectMirror(SoftObjectReference ref) { 1167 /* 1168 * This will remove the soft reference if it has not been 1169 * replaced in the cache. 1170 */ 1171 objectsByID.remove(ref.key()); 1172 } 1173 1174 StringReferenceImpl stringMirror(Instance id) { 1175 return (StringReferenceImpl) objectMirror(id); 1176 } 1177 1178 ArrayReferenceImpl arrayMirror(Array id) { 1179 return (ArrayReferenceImpl) objectMirror(id); 1180 } 1181 1182 ThreadReferenceImpl threadMirror(Instance id) { 1183 return (ThreadReferenceImpl) objectMirror(id); 1184 } 1185 1186 ThreadReferenceImpl threadMirror(JavaThread jt) { 1187 return (ThreadReferenceImpl) objectMirror(jt.getThreadObj()); 1188 } 1189 1190 ThreadGroupReferenceImpl threadGroupMirror(Instance id) { 1191 return (ThreadGroupReferenceImpl) objectMirror(id); 1192 } 1193 1194 ClassLoaderReferenceImpl classLoaderMirror(Instance id) { 1195 return (ClassLoaderReferenceImpl) objectMirror(id); 1196 } 1197 1198 ClassObjectReferenceImpl classObjectMirror(Instance id) { 1199 return (ClassObjectReferenceImpl) objectMirror(id); 1200 } 1201 1202 // Use of soft refs and caching stuff here has to be re-examined. 1203 // It might not make sense for JDI - SA. 1204 static private class SoftObjectReference extends SoftReference { 1205 int count; 1206 Object key; 1207 1208 SoftObjectReference(Object key, ObjectReferenceImpl mirror, 1209 ReferenceQueue queue) { 1210 super(mirror, queue); 1211 this.count = 1; 1212 this.key = key; 1213 } 1214 1215 int count() { 1216 return count; 1217 } 1218 1219 void incrementCount() { 1220 count++; 1221 } 1222 1223 Object key() { 1224 return key; 1225 } 1226 1227 ObjectReferenceImpl object() { 1228 return (ObjectReferenceImpl)get(); 1229 } 1230 } 1231 }