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