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 }