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