1 /*
   2  * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.jdi;
  26 
  27 import com.sun.jdi.*;
  28 import com.sun.jdi.event.EventQueue;
  29 import com.sun.jdi.request.EventRequestManager;
  30 
  31 import sun.jvm.hotspot.HotSpotAgent;
  32 import sun.jvm.hotspot.types.TypeDataBase;
  33 import sun.jvm.hotspot.oops.Klass;
  34 import sun.jvm.hotspot.oops.InstanceKlass;
  35 import sun.jvm.hotspot.oops.ArrayKlass;
  36 import sun.jvm.hotspot.oops.ObjArrayKlass;
  37 import sun.jvm.hotspot.oops.TypeArrayKlass;
  38 import sun.jvm.hotspot.oops.Oop;
  39 import sun.jvm.hotspot.oops.Instance;
  40 import sun.jvm.hotspot.oops.Array;
  41 import sun.jvm.hotspot.oops.ObjArray;
  42 import sun.jvm.hotspot.oops.TypeArray;
  43 import sun.jvm.hotspot.oops.Symbol;
  44 import sun.jvm.hotspot.oops.ObjectHeap;
  45 import sun.jvm.hotspot.oops.DefaultHeapVisitor;
  46 import sun.jvm.hotspot.oops.JVMDIClassStatus;
  47 import sun.jvm.hotspot.runtime.VM;
  48 import sun.jvm.hotspot.runtime.JavaThread;
  49 import sun.jvm.hotspot.memory.SystemDictionary;
  50 import sun.jvm.hotspot.memory.SymbolTable;
  51 import sun.jvm.hotspot.memory.Universe;
  52 import sun.jvm.hotspot.utilities.Assert;
  53 
  54 import java.util.List;
  55 import java.util.ArrayList;
  56 import java.util.Map;
  57 import java.util.Iterator;
  58 import java.util.Collections;
  59 import java.util.HashMap;
  60 import java.util.Observer;
  61 import java.util.StringTokenizer;
  62 import java.lang.ref.SoftReference;
  63 import java.lang.ref.ReferenceQueue;
  64 import java.lang.ref.Reference;
  65 
  66 public class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtualMachine {
  67 
  68     private HotSpotAgent     saAgent = new HotSpotAgent();
  69     private VM               saVM;
  70     private Universe         saUniverse;
  71     private SystemDictionary saSystemDictionary;
  72     private SymbolTable      saSymbolTable;
  73     private ObjectHeap       saObjectHeap;
  74 
  75     VM saVM() {
  76         return saVM;
  77     }
  78 
  79     SystemDictionary saSystemDictionary() {
  80         return saSystemDictionary;
  81     }
  82 
  83     SymbolTable saSymbolTable() {
  84         return saSymbolTable;
  85     }
  86 
  87     Universe saUniverse() {
  88         return saUniverse;
  89     }
  90 
  91     ObjectHeap saObjectHeap() {
  92         return saObjectHeap;
  93     }
  94 
  95     com.sun.jdi.VirtualMachineManager vmmgr;
  96 
  97     private final ThreadGroup             threadGroupForJDI;
  98 
  99     // Per-vm singletons for primitive types and for void.
 100     // singleton-ness protected by "synchronized(this)".
 101     private BooleanType theBooleanType;
 102     private ByteType    theByteType;
 103     private CharType    theCharType;
 104     private ShortType   theShortType;
 105     private IntegerType theIntegerType;
 106     private LongType    theLongType;
 107     private FloatType   theFloatType;
 108     private DoubleType  theDoubleType;
 109 
 110     private VoidType    theVoidType;
 111 
 112     private VoidValue voidVal;
 113     private Map       typesByID;             // Map<Klass, ReferenceTypeImpl>
 114     private List      typesBySignature;      // List<ReferenceTypeImpl> - used in signature search
 115     private boolean   retrievedAllTypes = false;
 116     private List      bootstrapClasses;      // all bootstrap classes
 117     private ArrayList allThreads;
 118     private ArrayList topLevelGroups;
 119     final   int       sequenceNumber;
 120 
 121     // ObjectReference cache
 122     // "objectsByID" protected by "synchronized(this)".
 123     private final Map            objectsByID = new HashMap();
 124     private final ReferenceQueue referenceQueue = new ReferenceQueue();
 125 
 126     // names of some well-known classes to jdi
 127     private Symbol javaLangString;
 128     private Symbol javaLangThread;
 129     private Symbol javaLangThreadGroup;
 130     private Symbol javaLangClass;
 131     private Symbol javaLangClassLoader;
 132 
 133     // used in ReferenceTypeImpl.isThrowableBacktraceField
 134     private Symbol javaLangThrowable;
 135 
 136     // names of classes used in array assignment check
 137     // refer to ArrayTypeImpl.isAssignableTo
 138     private Symbol javaLangObject;
 139     private Symbol javaLangCloneable;
 140     private Symbol javaIoSerializable;
 141 
 142     // symbol used in ClassTypeImpl.isEnum check
 143     private Symbol javaLangEnum;
 144 
 145     Symbol javaLangObject() {
 146         return javaLangObject;
 147     }
 148 
 149     Symbol javaLangCloneable() {
 150         return javaLangCloneable;
 151     }
 152 
 153     Symbol javaIoSerializable() {
 154         return javaIoSerializable;
 155     }
 156 
 157     Symbol javaLangEnum() {
 158         return javaLangEnum;
 159     }
 160 
 161     Symbol javaLangThrowable() {
 162         return javaLangThrowable;
 163     }
 164 
 165     // name of the current default stratum
 166     private String defaultStratum;
 167 
 168     // initialize known class name symbols
 169     private void initClassNameSymbols() {
 170         SymbolTable st = saSymbolTable();
 171         javaLangString = st.probe("java/lang/String");
 172         javaLangThread = st.probe("java/lang/Thread");
 173         javaLangThreadGroup = st.probe("java/lang/ThreadGroup");
 174         javaLangClass = st.probe("java/lang/Class");
 175         javaLangClassLoader = st.probe("java/lang/ClassLoader");
 176         javaLangThrowable = st.probe("java/lang/Throwable");
 177         javaLangObject = st.probe("java/lang/Object");
 178         javaLangCloneable = st.probe("java/lang/Cloneable");
 179         javaIoSerializable = st.probe("java/io/Serializable");
 180         javaLangEnum = st.probe("java/lang/Enum");
 181     }
 182 
 183     private void init() {
 184         saVM = VM.getVM();
 185         saUniverse = saVM.getUniverse();
 186         saSystemDictionary = saVM.getSystemDictionary();
 187         saSymbolTable = saVM.getSymbolTable();
 188         saObjectHeap = saVM.getObjectHeap();
 189         initClassNameSymbols();
 190     }
 191 
 192     static public VirtualMachineImpl createVirtualMachineForCorefile(VirtualMachineManager mgr,
 193                                                                      String javaExecutableName,
 194                                                                      String coreFileName,
 195                                                                      int sequenceNumber)
 196         throws Exception {
 197         if (Assert.ASSERTS_ENABLED) {
 198             Assert.that(coreFileName != null, "SA VirtualMachineImpl: core filename = null is not yet implemented");
 199         }
 200         if (Assert.ASSERTS_ENABLED) {
 201             Assert.that(javaExecutableName != null, "SA VirtualMachineImpl: java executable = null is not yet implemented");
 202         }
 203 
 204         VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber);
 205         try {
 206             myvm.saAgent.attach(javaExecutableName, coreFileName);
 207             myvm.init();
 208         } catch (Exception ee) {
 209             myvm.saAgent.detach();
 210             throw ee;
 211         }
 212         return myvm;
 213     }
 214 
 215     static public VirtualMachineImpl createVirtualMachineForPID(VirtualMachineManager mgr,
 216                                                                 int pid,
 217                                                                 int sequenceNumber)
 218         throws Exception {
 219 
 220         VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber);
 221         try {
 222             myvm.saAgent.attach(pid);
 223             myvm.init();
 224         } catch (Exception ee) {
 225             myvm.saAgent.detach();
 226             throw ee;
 227         }
 228         return myvm;
 229     }
 230 
 231     static public VirtualMachineImpl createVirtualMachineForServer(VirtualMachineManager mgr,
 232                                                                 String server,
 233                                                                 int sequenceNumber)
 234         throws Exception {
 235         if (Assert.ASSERTS_ENABLED) {
 236             Assert.that(server != null, "SA VirtualMachineImpl: DebugServer = null is not yet implemented");
 237         }
 238 
 239         VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber);
 240         try {
 241             myvm.saAgent.attach(server);
 242             myvm.init();
 243         } catch (Exception ee) {
 244             myvm.saAgent.detach();
 245             throw ee;
 246         }
 247         return myvm;
 248     }
 249 
 250 
 251     VirtualMachineImpl(VirtualMachineManager mgr, int sequenceNumber)
 252         throws Exception {
 253         super(null);  // Can't use super(this)
 254         vm = this;
 255 
 256         this.sequenceNumber = sequenceNumber;
 257         this.vmmgr = mgr;
 258 
 259         /* Create ThreadGroup to be used by all threads servicing
 260          * this VM.
 261          */
 262         threadGroupForJDI = new ThreadGroup("JDI [" +
 263                                             this.hashCode() + "]");
 264 
 265         ((com.sun.tools.jdi.VirtualMachineManagerImpl)mgr).addVirtualMachine(this);
 266 
 267         // 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         return java.text.MessageFormat.format(java.util.ResourceBundle.
 802                                               getBundle("com.sun.tools.jdi.resources.jdi").getString("version_format"),
 803                                               "" + vmmgr.majorInterfaceVersion(),
 804                                               "" + vmmgr.minorInterfaceVersion(),
 805                                               name());
 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 }