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 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 268 // we reflectively use newly spec'ed class because our ALT_BOOTDIR 269 // is 1.4.2 and not 1.5. 270 private static Class vmCannotBeModifiedExceptionClass = null; 271 void throwNotReadOnlyException(String operation) { 272 RuntimeException re = null; 273 if (vmCannotBeModifiedExceptionClass == null) { 274 try { 275 vmCannotBeModifiedExceptionClass = Class.forName("com.sun.jdi.VMCannotBeModifiedException"); 276 } catch (ClassNotFoundException cnfe) { 277 vmCannotBeModifiedExceptionClass = UnsupportedOperationException.class; 278 } 279 } 280 try { 281 re = (RuntimeException) vmCannotBeModifiedExceptionClass.newInstance(); 282 } catch (Exception exp) { 283 re = new RuntimeException(exp.getMessage()); 284 } 285 throw re; 286 } 287 288 public boolean equals(Object obj) { 289 // Oh boy; big recursion troubles if we don't have this! 290 // See MirrorImpl.equals 291 return this == obj; 292 } 293 294 public int hashCode() { 295 // big recursion if we don't have this. See MirrorImpl.hashCode 296 return System.identityHashCode(this); 297 } 298 299 public List classesByName(String className) { 300 String signature = JNITypeParser.typeNameToSignature(className); 301 List list; 302 if (!retrievedAllTypes) { 303 retrieveAllClasses(); 304 } 305 list = findReferenceTypes(signature); 306 return Collections.unmodifiableList(list); 307 } 308 309 public List allClasses() { 310 if (!retrievedAllTypes) { 311 retrieveAllClasses(); 312 } 313 ArrayList a; 314 synchronized (this) { 315 a = new ArrayList(typesBySignature); 316 } 317 return Collections.unmodifiableList(a); 318 } 319 320 // classes loaded by bootstrap loader 321 List bootstrapClasses() { 322 if (bootstrapClasses == null) { 323 bootstrapClasses = new ArrayList(); 324 List all = allClasses(); 325 for (Iterator itr = all.iterator(); itr.hasNext();) { 326 ReferenceType type = (ReferenceType) itr.next(); 327 if (type.classLoader() == null) { 328 bootstrapClasses.add(type); 329 } 330 } 331 } 332 return bootstrapClasses; 333 } 334 335 private synchronized List findReferenceTypes(String signature) { 336 if (typesByID == null) { 337 return new ArrayList(0); 338 } 339 340 // we haven't sorted types by signatures. But we can take 341 // advantage of comparing symbols instead of name. In the worst 342 // case, we will be comparing N addresses rather than N strings 343 // where N being total no. of classes in allClasses() list. 344 345 // The signature could be Lx/y/z; or [.... 346 // If it is Lx/y/z; the internal type name is x/y/x 347 // for array klasses internal type name is same as 348 // signature 349 String typeName = null; 350 if (signature.charAt(0) == 'L') { 351 typeName = signature.substring(1, signature.length() - 1); 352 } else { 353 typeName = signature; 354 } 355 356 Symbol typeNameSym = saSymbolTable().probe(typeName); 357 // if there is no symbol in VM, then we wouldn't have that type 358 if (typeNameSym == null) { 359 return new ArrayList(0); 360 } 361 362 Iterator iter = typesBySignature.iterator(); 363 List list = new ArrayList(); 364 while (iter.hasNext()) { 365 // We have cached type name as symbol in reference type 366 ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next(); 367 if (typeNameSym.equals(type.typeNameAsSymbol())) { 368 list.add(type); 369 } 370 } 371 return list; 372 } 373 374 private void retrieveAllClasses() { 375 final List saKlasses = new ArrayList(); 376 SystemDictionary.ClassVisitor visitor = new SystemDictionary.ClassVisitor() { 377 public void visit(Klass k) { 378 for (Klass l = k; l != null; l = l.arrayKlassOrNull()) { 379 // for non-array classes filter out un-prepared classes 380 // refer to 'allClasses' in share/back/VirtualMachineImpl.c 381 if (l instanceof ArrayKlass) { 382 saKlasses.add(l); 383 } else { 384 int status = l.getClassStatus(); 385 if ((status & JVMDIClassStatus.PREPARED) != 0) { 386 saKlasses.add(l); 387 } 388 } 389 } 390 } 391 }; 392 393 // refer to jvmtiGetLoadedClasses.cpp - getLoadedClasses in VM code. 394 395 // classes from SystemDictionary 396 saSystemDictionary.classesDo(visitor); 397 398 // From SystemDictionary we do not get primitive single 399 // dimensional array classes. add primitive single dimensional array 400 // klasses from Universe. 401 saVM.getUniverse().basicTypeClassesDo(visitor); 402 403 // Hold lock during processing to improve performance 404 // and to have safe check/set of retrievedAllTypes 405 synchronized (this) { 406 if (!retrievedAllTypes) { 407 // Number of classes 408 int count = saKlasses.size(); 409 for (int ii = 0; ii < count; ii++) { 410 Klass kk = (Klass)saKlasses.get(ii); 411 ReferenceTypeImpl type = referenceType(kk); 412 } 413 retrievedAllTypes = true; 414 } 415 } 416 } 417 418 ReferenceTypeImpl referenceType(Klass kk) { 419 ReferenceTypeImpl retType = null; 420 synchronized (this) { 421 if (typesByID != null) { 422 retType = (ReferenceTypeImpl)typesByID.get(kk); 423 } 424 if (retType == null) { 425 retType = addReferenceType(kk); 426 } 427 } 428 return retType; 429 } 430 431 private void initReferenceTypes() { 432 typesByID = new HashMap(); 433 typesBySignature = new ArrayList(); 434 } 435 436 private synchronized ReferenceTypeImpl addReferenceType(Klass kk) { 437 if (typesByID == null) { 438 initReferenceTypes(); 439 } 440 ReferenceTypeImpl newRefType = null; 441 if (kk instanceof ObjArrayKlass || kk instanceof TypeArrayKlass) { 442 newRefType = new ArrayTypeImpl(this, (ArrayKlass)kk); 443 } else if (kk instanceof InstanceKlass) { 444 if (kk.isInterface()) { 445 newRefType = new InterfaceTypeImpl(this, (InstanceKlass)kk); 446 } else { 447 newRefType = new ClassTypeImpl(this, (InstanceKlass)kk); 448 } 449 } else { 450 throw new RuntimeException("should not reach here"); 451 } 452 453 typesByID.put(kk, newRefType); 454 typesBySignature.add(newRefType); 455 return newRefType; 456 } 457 458 ThreadGroup threadGroupForJDI() { 459 return threadGroupForJDI; 460 } 461 462 public void redefineClasses(Map classToBytes) { 463 throwNotReadOnlyException("VirtualMachineImpl.redefineClasses()"); 464 } 465 466 private List getAllThreads() { 467 if (allThreads == null) { 468 allThreads = new ArrayList(10); // Might be enough, might not be 469 for (sun.jvm.hotspot.runtime.JavaThread thread = 470 saVM.getThreads().first(); thread != null; 471 thread = thread.next()) { 472 // refer to JvmtiEnv::GetAllThreads in jvmtiEnv.cpp. 473 // filter out the hidden-from-external-view threads. 474 if (thread.isHiddenFromExternalView() == false) { 475 ThreadReferenceImpl myThread = threadMirror(thread); 476 allThreads.add(myThread); 477 } 478 } 479 } 480 return allThreads; 481 } 482 483 public List allThreads() { //fixme jjh 484 return Collections.unmodifiableList(getAllThreads()); 485 } 486 487 public void suspend() { 488 throwNotReadOnlyException("VirtualMachineImpl.suspend()"); 489 } 490 491 public void resume() { 492 throwNotReadOnlyException("VirtualMachineImpl.resume()"); 493 } 494 495 public List topLevelThreadGroups() { //fixme jjh 496 // The doc for ThreadGroup says that The top-level thread group 497 // is the only thread group whose parent is null. This means there is 498 // only one top level thread group. There will be a thread in this 499 // group so we will just find a thread whose threadgroup has no parent 500 // and that will be it. 501 502 if (topLevelGroups == null) { 503 topLevelGroups = new ArrayList(1); 504 Iterator myIt = getAllThreads().iterator(); 505 while (myIt.hasNext()) { 506 ThreadReferenceImpl myThread = (ThreadReferenceImpl)myIt.next(); 507 ThreadGroupReference myGroup = myThread.threadGroup(); 508 ThreadGroupReference myParent = myGroup.parent(); 509 if (myGroup.parent() == null) { 510 topLevelGroups.add(myGroup); 511 break; 512 } 513 } 514 } 515 return Collections.unmodifiableList(topLevelGroups); 516 } 517 518 public EventQueue eventQueue() { 519 throwNotReadOnlyException("VirtualMachine.eventQueue()"); 520 return null; 521 } 522 523 public EventRequestManager eventRequestManager() { 524 throwNotReadOnlyException("VirtualMachineImpl.eventRequestManager()"); 525 return null; 526 } 527 528 public BooleanValue mirrorOf(boolean value) { 529 return new BooleanValueImpl(this,value); 530 } 531 532 public ByteValue mirrorOf(byte value) { 533 return new ByteValueImpl(this,value); 534 } 535 536 public CharValue mirrorOf(char value) { 537 return new CharValueImpl(this,value); 538 } 539 540 public ShortValue mirrorOf(short value) { 541 return new ShortValueImpl(this,value); 542 } 543 544 public IntegerValue mirrorOf(int value) { 545 return new IntegerValueImpl(this,value); 546 } 547 548 public LongValue mirrorOf(long value) { 549 return new LongValueImpl(this,value); 550 } 551 552 public FloatValue mirrorOf(float value) { 553 return new FloatValueImpl(this,value); 554 } 555 556 public DoubleValue mirrorOf(double value) { 557 return new DoubleValueImpl(this,value); 558 } 559 560 public StringReference mirrorOf(String value) { 561 throwNotReadOnlyException("VirtualMachinestop.mirrorOf(String)"); 562 return null; 563 } 564 565 public VoidValue mirrorOfVoid() { 566 if (voidVal == null) { 567 voidVal = new VoidValueImpl(this); 568 } 569 return voidVal; 570 } 571 572 573 public Process process() { 574 throwNotReadOnlyException("VirtualMachine.process"); 575 return null; 576 } 577 578 // dispose observer for Class re-use. refer to ConnectorImpl. 579 private Observer disposeObserver; 580 581 // ConnectorImpl loaded by a different class loader can not access it. 582 // i.e., runtime package of <ConnectorImpl, L1> is not the same that of 583 // <VirtualMachineImpl, L2> when L1 != L2. So, package private method 584 // can be called reflectively after using setAccessible(true). 585 586 void setDisposeObserver(Observer observer) { 587 disposeObserver = observer; 588 } 589 590 private void notifyDispose() { 591 if (Assert.ASSERTS_ENABLED) { 592 Assert.that(disposeObserver != null, "null VM.dispose observer"); 593 } 594 disposeObserver.update(null, null); 595 } 596 597 public void dispose() { 598 saAgent.detach(); 599 notifyDispose(); 600 } 601 602 public void exit(int exitCode) { 603 throwNotReadOnlyException("VirtualMachine.exit(int)"); 604 } 605 606 public boolean canBeModified() { 607 return false; 608 } 609 610 public boolean canWatchFieldModification() { 611 return false; 612 } 613 614 public boolean canWatchFieldAccess() { 615 return false; 616 } 617 618 public boolean canGetBytecodes() { 619 return true; 620 } 621 622 public boolean canGetSyntheticAttribute() { 623 return true; 624 } 625 626 // FIXME: For now, all monitor capabilities are disabled 627 public boolean canGetOwnedMonitorInfo() { 628 return false; 629 } 630 631 public boolean canGetCurrentContendedMonitor() { 632 return false; 633 } 634 635 public boolean canGetMonitorInfo() { 636 return false; 637 } 638 639 // because this SA works only with 1.5 and update releases 640 // this should always succeed unlike JVMDI/JDI. 641 public boolean canGet1_5LanguageFeatures() { 642 return true; 643 } 644 645 public boolean canUseInstanceFilters() { 646 return false; 647 } 648 649 public boolean canRedefineClasses() { 650 return false; 651 } 652 653 public boolean canAddMethod() { 654 return false; 655 } 656 657 public boolean canUnrestrictedlyRedefineClasses() { 658 return false; 659 } 660 661 public boolean canPopFrames() { 662 return false; 663 } 664 665 public boolean canGetSourceDebugExtension() { 666 // We can use InstanceKlass.getSourceDebugExtension only if 667 // ClassFileParser parsed the info. But, ClassFileParser parses 668 // SourceDebugExtension attribute only if corresponding JVMDI/TI 669 // capability is set to true. Currently, vmStructs does not expose 670 // JVMDI/TI capabilities and hence we conservatively assume false. 671 return false; 672 } 673 674 public boolean canRequestVMDeathEvent() { 675 return false; 676 } 677 678 // new method since 1.6 679 public boolean canForceEarlyReturn() { 680 return false; 681 } 682 683 // new method since 1.6 684 public boolean canGetConstantPool() { 685 return true; 686 } 687 688 // new method since 1.6 689 public boolean canGetClassFileVersion() { 690 return true; 691 } 692 693 // new method since 1.6. 694 public boolean canGetMethodReturnValues() { 695 return false; 696 } 697 698 // new method since 1.6 699 // Real body will be supplied later. 700 public boolean canGetInstanceInfo() { 701 return true; 702 } 703 704 // new method since 1.6 705 public boolean canUseSourceNameFilters() { 706 return false; 707 } 708 709 // new method since 1.6. 710 public boolean canRequestMonitorEvents() { 711 return false; 712 } 713 714 // new method since 1.6. 715 public boolean canGetMonitorFrameInfo() { 716 return true; 717 } 718 719 // new method since 1.6 720 // Real body will be supplied later. 721 public long[] instanceCounts(List classes) { 722 if (!canGetInstanceInfo()) { 723 throw new UnsupportedOperationException( 724 "target does not support getting instances"); 725 } 726 727 final long[] retValue = new long[classes.size()] ; 728 729 final Klass [] klassArray = new Klass[classes.size()]; 730 731 boolean allAbstractClasses = true; 732 for (int i=0; i < classes.size(); i++) { 733 ReferenceTypeImpl rti = (ReferenceTypeImpl)classes.get(i); 734 klassArray[i] = rti.ref(); 735 retValue[i]=0; 736 if (!(rti.isAbstract() || ((ReferenceType)rti instanceof InterfaceType))) { 737 allAbstractClasses = false; 738 } 739 } 740 741 if (allAbstractClasses) { 742 return retValue; 743 } 744 final int size = classes.size(); 745 saObjectHeap.iterate(new DefaultHeapVisitor() { 746 public boolean doObj(Oop oop) { 747 for (int i=0; i < size; i++) { 748 if (klassArray[i].equals(oop.getKlass())) { 749 retValue[i]++; 750 break; 751 } 752 } 753 return false; 754 } 755 }); 756 757 return retValue; 758 } 759 760 private List getPath (String pathName) { 761 String cp = saVM.getSystemProperty(pathName); 762 String pathSep = saVM.getSystemProperty("path.separator"); 763 ArrayList al = new ArrayList(); 764 StringTokenizer st = new StringTokenizer(cp, pathSep); 765 while (st.hasMoreTokens()) { 766 al.add(st.nextToken()); 767 } 768 al.trimToSize(); 769 return al; 770 } 771 772 public List classPath() { 773 return getPath("java.class.path"); 774 } 775 776 public List bootClassPath() { 777 return getPath("sun.boot.class.path"); 778 } 779 780 public String baseDirectory() { 781 return saVM.getSystemProperty("user.dir"); 782 } 783 784 public void setDefaultStratum(String stratum) { 785 defaultStratum = stratum; 786 } 787 788 public String getDefaultStratum() { 789 return defaultStratum; 790 } 791 792 public String description() { 793 return java.text.MessageFormat.format(java.util.ResourceBundle. 794 getBundle("com.sun.tools.jdi.resources.jdi").getString("version_format"), 795 "" + vmmgr.majorInterfaceVersion(), 796 "" + vmmgr.minorInterfaceVersion(), 797 name()); 798 } 799 800 public String version() { 801 return saVM.getSystemProperty("java.version"); 802 } 803 804 public String name() { 805 StringBuffer sb = new StringBuffer(); 806 sb.append("JVM version "); 807 sb.append(version()); 808 sb.append(" ("); 809 sb.append(saVM.getSystemProperty("java.vm.name")); 810 sb.append(", "); 811 sb.append(saVM.getSystemProperty("java.vm.info")); 812 sb.append(")"); 813 return sb.toString(); 814 } 815 816 // from interface Mirror 817 public VirtualMachine virtualMachine() { 818 return this; 819 } 820 821 public String toString() { 822 return name(); 823 } 824 825 public void setDebugTraceMode(int traceFlags) { 826 // spec. says output is implementation dependent 827 // and trace mode may be ignored. we ignore it :-) 828 } 829 830 // heap walking API 831 832 // capability check 833 public boolean canWalkHeap() { 834 return true; 835 } 836 837 // return a list of all objects in heap 838 public List/*<ObjectReference>*/ allObjects() { 839 final List objects = new ArrayList(0); 840 saObjectHeap.iterate( 841 new DefaultHeapVisitor() { 842 public boolean doObj(Oop oop) { 843 objects.add(objectMirror(oop)); 844 return false; 845 } 846 }); 847 return objects; 848 } 849 850 // equivalent to objectsByType(type, true) 851 public List/*<ObjectReference>*/ objectsByType(ReferenceType type) { 852 return objectsByType(type, true); 853 } 854 855 // returns objects of type exactly equal to given type 856 private List/*<ObjectReference>*/ objectsByExactType(ReferenceType type) { 857 final List objects = new ArrayList(0); 858 final Klass givenKls = ((ReferenceTypeImpl)type).ref(); 859 saObjectHeap.iterate(new DefaultHeapVisitor() { 860 public boolean doObj(Oop oop) { 861 if (givenKls.equals(oop.getKlass())) { 862 objects.add(objectMirror(oop)); 863 } 864 return false; 865 } 866 }); 867 return objects; 868 } 869 870 // returns objects of given type as well as it's subtypes 871 private List/*<ObjectReference>*/ objectsBySubType(ReferenceType type) { 872 final List objects = new ArrayList(0); 873 final ReferenceType givenType = type; 874 saObjectHeap.iterate(new DefaultHeapVisitor() { 875 public boolean doObj(Oop oop) { 876 ReferenceTypeImpl curType = (ReferenceTypeImpl) referenceType(oop.getKlass()); 877 if (curType.isAssignableTo(givenType)) { 878 objects.add(objectMirror(oop)); 879 } 880 return false; 881 } 882 }); 883 return objects; 884 } 885 886 // includeSubtypes - do you want to include subclass/subtype instances of given 887 // ReferenceType or do we want objects of exact type only? 888 public List/*<ObjectReference>*/ objectsByType(ReferenceType type, boolean includeSubtypes) { 889 Klass kls = ((ReferenceTypeImpl)type).ref(); 890 if (kls instanceof InstanceKlass) { 891 InstanceKlass ik = (InstanceKlass) kls; 892 if (ik.isInterface()) { 893 if (ik.nofImplementors() == 0L) { 894 return new ArrayList(0); 895 } 896 } else { 897 // if the Klass is final or if there are no subklasses loaded yet 898 if (ik.getAccessFlagsObj().isFinal() || ik.getSubklassKlass() == null) { 899 includeSubtypes = false; 900 } 901 } 902 } else { 903 // no subtypes for primitive array types 904 ArrayTypeImpl arrayType = (ArrayTypeImpl) type; 905 try { 906 Type componentType = arrayType.componentType(); 907 if (componentType instanceof PrimitiveType) { 908 includeSubtypes = false; 909 } 910 } catch (ClassNotLoadedException cnle) { 911 // ignore. component type not yet loaded 912 } 913 } 914 915 if (includeSubtypes) { 916 return objectsBySubType(type); 917 } else { 918 return objectsByExactType(type); 919 } 920 } 921 922 Type findBootType(String signature) throws ClassNotLoadedException { 923 List types = allClasses(); 924 Iterator iter = types.iterator(); 925 while (iter.hasNext()) { 926 ReferenceType type = (ReferenceType)iter.next(); 927 if ((type.classLoader() == null) && 928 (type.signature().equals(signature))) { 929 return type; 930 } 931 } 932 JNITypeParser parser = new JNITypeParser(signature); 933 throw new ClassNotLoadedException(parser.typeName(), 934 "Type " + parser.typeName() + " not loaded"); 935 } 936 937 BooleanType theBooleanType() { 938 if (theBooleanType == null) { 939 synchronized(this) { 940 if (theBooleanType == null) { 941 theBooleanType = new BooleanTypeImpl(this); 942 } 943 } 944 } 945 return theBooleanType; 946 } 947 948 ByteType theByteType() { 949 if (theByteType == null) { 950 synchronized(this) { 951 if (theByteType == null) { 952 theByteType = new ByteTypeImpl(this); 953 } 954 } 955 } 956 return theByteType; 957 } 958 959 CharType theCharType() { 960 if (theCharType == null) { 961 synchronized(this) { 962 if (theCharType == null) { 963 theCharType = new CharTypeImpl(this); 964 } 965 } 966 } 967 return theCharType; 968 } 969 970 ShortType theShortType() { 971 if (theShortType == null) { 972 synchronized(this) { 973 if (theShortType == null) { 974 theShortType = new ShortTypeImpl(this); 975 } 976 } 977 } 978 return theShortType; 979 } 980 981 IntegerType theIntegerType() { 982 if (theIntegerType == null) { 983 synchronized(this) { 984 if (theIntegerType == null) { 985 theIntegerType = new IntegerTypeImpl(this); 986 } 987 } 988 } 989 return theIntegerType; 990 } 991 992 LongType theLongType() { 993 if (theLongType == null) { 994 synchronized(this) { 995 if (theLongType == null) { 996 theLongType = new LongTypeImpl(this); 997 } 998 } 999 } 1000 return theLongType; 1001 } 1002 1003 FloatType theFloatType() { 1004 if (theFloatType == null) { 1005 synchronized(this) { 1006 if (theFloatType == null) { 1007 theFloatType = new FloatTypeImpl(this); 1008 } 1009 } 1010 } 1011 return theFloatType; 1012 } 1013 1014 DoubleType theDoubleType() { 1015 if (theDoubleType == null) { 1016 synchronized(this) { 1017 if (theDoubleType == null) { 1018 theDoubleType = new DoubleTypeImpl(this); 1019 } 1020 } 1021 } 1022 return theDoubleType; 1023 } 1024 1025 VoidType theVoidType() { 1026 if (theVoidType == null) { 1027 synchronized(this) { 1028 if (theVoidType == null) { 1029 theVoidType = new VoidTypeImpl(this); 1030 } 1031 } 1032 } 1033 return theVoidType; 1034 } 1035 1036 PrimitiveType primitiveTypeMirror(char tag) { 1037 switch (tag) { 1038 case 'Z': 1039 return theBooleanType(); 1040 case 'B': 1041 return theByteType(); 1042 case 'C': 1043 return theCharType(); 1044 case 'S': 1045 return theShortType(); 1046 case 'I': 1047 return theIntegerType(); 1048 case 'J': 1049 return theLongType(); 1050 case 'F': 1051 return theFloatType(); 1052 case 'D': 1053 return theDoubleType(); 1054 default: 1055 throw new IllegalArgumentException("Unrecognized primitive tag " + tag); 1056 } 1057 } 1058 1059 private void processQueue() { 1060 Reference ref; 1061 while ((ref = referenceQueue.poll()) != null) { 1062 SoftObjectReference softRef = (SoftObjectReference)ref; 1063 removeObjectMirror(softRef); 1064 } 1065 } 1066 1067 // Address value is used as uniqueID by ObjectReferenceImpl 1068 long getAddressValue(Oop obj) { 1069 return vm.saVM.getDebugger().getAddressValue(obj.getHandle()); 1070 } 1071 1072 synchronized ObjectReferenceImpl objectMirror(Oop key) { 1073 1074 // Handle any queue elements that are not strongly reachable 1075 processQueue(); 1076 1077 if (key == null) { 1078 return null; 1079 } 1080 ObjectReferenceImpl object = null; 1081 1082 /* 1083 * Attempt to retrieve an existing object object reference 1084 */ 1085 SoftObjectReference ref = (SoftObjectReference)objectsByID.get(key); 1086 if (ref != null) { 1087 object = ref.object(); 1088 } 1089 1090 /* 1091 * If the object wasn't in the table, or it's soft reference was 1092 * cleared, create a new instance. 1093 */ 1094 if (object == null) { 1095 if (key instanceof Instance) { 1096 // look for well-known classes 1097 Symbol className = key.getKlass().getName(); 1098 if (Assert.ASSERTS_ENABLED) { 1099 Assert.that(className != null, "Null class name"); 1100 } 1101 Instance inst = (Instance) key; 1102 if (className.equals(javaLangString)) { 1103 object = new StringReferenceImpl(this, inst); 1104 } else if (className.equals(javaLangThread)) { 1105 object = new ThreadReferenceImpl(this, inst); 1106 } else if (className.equals(javaLangThreadGroup)) { 1107 object = new ThreadGroupReferenceImpl(this, inst); 1108 } else if (className.equals(javaLangClass)) { 1109 object = new ClassObjectReferenceImpl(this, inst); 1110 } else if (className.equals(javaLangClassLoader)) { 1111 object = new ClassLoaderReferenceImpl(this, inst); 1112 } else { 1113 // not a well-known class. But the base class may be 1114 // one of the known classes. 1115 Klass kls = key.getKlass().getSuper(); 1116 while (kls != null) { 1117 className = kls.getName(); 1118 // java.lang.Class and java.lang.String are final classes 1119 if (className.equals(javaLangThread)) { 1120 object = new ThreadReferenceImpl(this, inst); 1121 break; 1122 } else if(className.equals(javaLangThreadGroup)) { 1123 object = new ThreadGroupReferenceImpl(this, inst); 1124 break; 1125 } else if (className.equals(javaLangClassLoader)) { 1126 object = new ClassLoaderReferenceImpl(this, inst); 1127 break; 1128 } 1129 kls = kls.getSuper(); 1130 } 1131 1132 if (object == null) { 1133 // create generic object reference 1134 object = new ObjectReferenceImpl(this, inst); 1135 } 1136 } 1137 } else if (key instanceof TypeArray) { 1138 object = new ArrayReferenceImpl(this, (Array) key); 1139 } else if (key instanceof ObjArray) { 1140 object = new ArrayReferenceImpl(this, (Array) key); 1141 } else { 1142 throw new RuntimeException("unexpected object type " + key); 1143 } 1144 ref = new SoftObjectReference(key, object, referenceQueue); 1145 1146 /* 1147 * If there was no previous entry in the table, we add one here 1148 * If the previous entry was cleared, we replace it here. 1149 */ 1150 objectsByID.put(key, ref); 1151 } else { 1152 ref.incrementCount(); 1153 } 1154 1155 return object; 1156 } 1157 1158 synchronized void removeObjectMirror(SoftObjectReference ref) { 1159 /* 1160 * This will remove the soft reference if it has not been 1161 * replaced in the cache. 1162 */ 1163 objectsByID.remove(ref.key()); 1164 } 1165 1166 StringReferenceImpl stringMirror(Instance id) { 1167 return (StringReferenceImpl) objectMirror(id); 1168 } 1169 1170 ArrayReferenceImpl arrayMirror(Array id) { 1171 return (ArrayReferenceImpl) objectMirror(id); 1172 } 1173 1174 ThreadReferenceImpl threadMirror(Instance id) { 1175 return (ThreadReferenceImpl) objectMirror(id); 1176 } 1177 1178 ThreadReferenceImpl threadMirror(JavaThread jt) { 1179 return (ThreadReferenceImpl) objectMirror(jt.getThreadObj()); 1180 } 1181 1182 ThreadGroupReferenceImpl threadGroupMirror(Instance id) { 1183 return (ThreadGroupReferenceImpl) objectMirror(id); 1184 } 1185 1186 ClassLoaderReferenceImpl classLoaderMirror(Instance id) { 1187 return (ClassLoaderReferenceImpl) objectMirror(id); 1188 } 1189 1190 ClassObjectReferenceImpl classObjectMirror(Instance id) { 1191 return (ClassObjectReferenceImpl) objectMirror(id); 1192 } 1193 1194 // Use of soft refs and caching stuff here has to be re-examined. 1195 // It might not make sense for JDI - SA. 1196 static private class SoftObjectReference extends SoftReference { 1197 int count; 1198 Object key; 1199 1200 SoftObjectReference(Object key, ObjectReferenceImpl mirror, 1201 ReferenceQueue queue) { 1202 super(mirror, queue); 1203 this.count = 1; 1204 this.key = key; 1205 } 1206 1207 int count() { 1208 return count; 1209 } 1210 1211 void incrementCount() { 1212 count++; 1213 } 1214 1215 Object key() { 1216 return key; 1217 } 1218 1219 ObjectReferenceImpl object() { 1220 return (ObjectReferenceImpl)get(); 1221 } 1222 } 1223 }