1 /*
   2  * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 package sun.jvm.hotspot.jdi;
  26 
  27 import com.sun.jdi.*;
  28 import com.sun.jdi.event.EventQueue;
  29 import com.sun.jdi.request.EventRequestManager;
  30 
  31 import sun.jvm.hotspot.HotSpotAgent;
  32 import sun.jvm.hotspot.types.TypeDataBase;
  33 import sun.jvm.hotspot.oops.Klass;
  34 import sun.jvm.hotspot.oops.InstanceKlass;
  35 import sun.jvm.hotspot.oops.ArrayKlass;
  36 import sun.jvm.hotspot.oops.ObjArrayKlass;
  37 import sun.jvm.hotspot.oops.TypeArrayKlass;
  38 import sun.jvm.hotspot.oops.Oop;
  39 import sun.jvm.hotspot.oops.Instance;
  40 import sun.jvm.hotspot.oops.Array;
  41 import sun.jvm.hotspot.oops.ObjArray;
  42 import sun.jvm.hotspot.oops.TypeArray;
  43 import sun.jvm.hotspot.oops.Symbol;
  44 import sun.jvm.hotspot.oops.ObjectHeap;
  45 import sun.jvm.hotspot.oops.DefaultHeapVisitor;
  46 import sun.jvm.hotspot.oops.JVMDIClassStatus;
  47 import sun.jvm.hotspot.runtime.VM;
  48 import sun.jvm.hotspot.runtime.JavaThread;
  49 import sun.jvm.hotspot.memory.SystemDictionary;
  50 import sun.jvm.hotspot.memory.SymbolTable;
  51 import sun.jvm.hotspot.memory.Universe;
  52 import sun.jvm.hotspot.utilities.Assert;
  53 
  54 import java.util.List;
  55 import java.util.ArrayList;
  56 import java.util.Map;
  57 import java.util.Iterator;
  58 import java.util.Collections;
  59 import java.util.HashMap;
  60 import java.util.Observer;
  61 import java.util.StringTokenizer;
  62 import java.lang.ref.SoftReference;
  63 import java.lang.ref.ReferenceQueue;
  64 import java.lang.ref.Reference;
  65 
  66 public class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtualMachine {
  67 
  68     private HotSpotAgent     saAgent = new HotSpotAgent();
  69     private VM               saVM;
  70     private Universe         saUniverse;
  71     private SystemDictionary saSystemDictionary;
  72     private SymbolTable      saSymbolTable;
  73     private ObjectHeap       saObjectHeap;
  74 
  75     VM saVM() {
  76         return saVM;
  77     }
  78 
  79     SystemDictionary saSystemDictionary() {
  80         return saSystemDictionary;
  81     }
  82 
  83     SymbolTable saSymbolTable() {
  84         return saSymbolTable;
  85     }
  86 
  87     Universe saUniverse() {
  88         return saUniverse;
  89     }
  90 
  91     ObjectHeap saObjectHeap() {
  92         return saObjectHeap;
  93     }
  94 
  95     com.sun.jdi.VirtualMachineManager vmmgr;
  96 
  97     private final ThreadGroup             threadGroupForJDI;
  98 
  99     // Per-vm singletons for primitive types and for void.
 100     // singleton-ness protected by "synchronized(this)".
 101     private BooleanType theBooleanType;
 102     private ByteType    theByteType;
 103     private CharType    theCharType;
 104     private ShortType   theShortType;
 105     private IntegerType theIntegerType;
 106     private LongType    theLongType;
 107     private FloatType   theFloatType;
 108     private DoubleType  theDoubleType;
 109 
 110     private VoidType    theVoidType;
 111 
 112     private VoidValue voidVal;
 113     private Map       typesByID;             // Map<Klass, ReferenceTypeImpl>
 114     private List      typesBySignature;      // List<ReferenceTypeImpl> - used in signature search
 115     private boolean   retrievedAllTypes = false;
 116     private List      bootstrapClasses;      // all bootstrap classes
 117     private ArrayList allThreads;
 118     private ArrayList topLevelGroups;
 119     final   int       sequenceNumber;
 120 
 121     // ObjectReference cache
 122     // "objectsByID" protected by "synchronized(this)".
 123     private final Map            objectsByID = new HashMap();
 124     private final ReferenceQueue referenceQueue = new ReferenceQueue();
 125 
 126     // names of some well-known classes to jdi
 127     private Symbol javaLangString;
 128     private Symbol javaLangThread;
 129     private Symbol javaLangThreadGroup;
 130     private Symbol javaLangClass;
 131     private Symbol javaLangClassLoader;
 132 
 133     // used in ReferenceTypeImpl.isThrowableBacktraceField
 134     private Symbol javaLangThrowable;
 135 
 136     // names of classes used in array assignment check
 137     // refer to ArrayTypeImpl.isAssignableTo
 138     private Symbol javaLangObject;
 139     private Symbol javaLangCloneable;
 140     private Symbol javaIoSerializable;
 141 
 142     // symbol used in ClassTypeImpl.isEnum check
 143     private Symbol javaLangEnum;
 144 
 145     Symbol javaLangObject() {
 146         return javaLangObject;
 147     }
 148 
 149     Symbol javaLangCloneable() {
 150         return javaLangCloneable;
 151     }
 152 
 153     Symbol javaIoSerializable() {
 154         return javaIoSerializable;
 155     }
 156 
 157     Symbol javaLangEnum() {
 158         return javaLangEnum;
 159     }
 160 
 161     Symbol javaLangThrowable() {
 162         return javaLangThrowable;
 163     }
 164 
 165     // name of the current default stratum
 166     private String defaultStratum;
 167 
 168     // initialize known class name symbols
 169     private void initClassNameSymbols() {
 170         SymbolTable st = saSymbolTable();
 171         javaLangString = st.probe("java/lang/String");
 172         javaLangThread = st.probe("java/lang/Thread");
 173         javaLangThreadGroup = st.probe("java/lang/ThreadGroup");
 174         javaLangClass = st.probe("java/lang/Class");
 175         javaLangClassLoader = st.probe("java/lang/ClassLoader");
 176         javaLangThrowable = st.probe("java/lang/Throwable");
 177         javaLangObject = st.probe("java/lang/Object");
 178         javaLangCloneable = st.probe("java/lang/Cloneable");
 179         javaIoSerializable = st.probe("java/io/Serializable");
 180         javaLangEnum = st.probe("java/lang/Enum");
 181     }
 182 
 183     private void init() {
 184         saVM = VM.getVM();
 185         saUniverse = saVM.getUniverse();
 186         saSystemDictionary = saVM.getSystemDictionary();
 187         saSymbolTable = saVM.getSymbolTable();
 188         saObjectHeap = saVM.getObjectHeap();
 189         initClassNameSymbols();
 190     }
 191 
 192     static public VirtualMachineImpl createVirtualMachineForCorefile(VirtualMachineManager mgr,
 193                                                                      String javaExecutableName,
 194                                                                      String coreFileName,
 195                                                                      int sequenceNumber)
 196         throws Exception {
 197         if (Assert.ASSERTS_ENABLED) {
 198             Assert.that(coreFileName != null, "SA VirtualMachineImpl: core filename = null is not yet implemented");
 199         }
 200         if (Assert.ASSERTS_ENABLED) {
 201             Assert.that(javaExecutableName != null, "SA VirtualMachineImpl: java executable = null is not yet implemented");
 202         }
 203 
 204         VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber);
 205         try {
 206             myvm.saAgent.attach(javaExecutableName, coreFileName);
 207             myvm.init();
 208         } catch (Exception ee) {
 209             myvm.saAgent.detach();
 210             throw ee;
 211         }
 212         return myvm;
 213     }
 214 
 215     static public VirtualMachineImpl createVirtualMachineForPID(VirtualMachineManager mgr,
 216                                                                 int pid,
 217                                                                 int sequenceNumber)
 218         throws Exception {
 219 
 220         VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber);
 221         try {
 222             myvm.saAgent.attach(pid);
 223             myvm.init();
 224         } catch (Exception ee) {
 225             myvm.saAgent.detach();
 226             throw ee;
 227         }
 228         return myvm;
 229     }
 230 
 231     static public VirtualMachineImpl createVirtualMachineForServer(VirtualMachineManager mgr,
 232                                                                 String server,
 233                                                                 int sequenceNumber)
 234         throws Exception {
 235         if (Assert.ASSERTS_ENABLED) {
 236             Assert.that(server != null, "SA VirtualMachineImpl: DebugServer = null is not yet implemented");
 237         }
 238 
 239         VirtualMachineImpl myvm = new VirtualMachineImpl(mgr, sequenceNumber);
 240         try {
 241             myvm.saAgent.attach(server);
 242             myvm.init();
 243         } catch (Exception ee) {
 244             myvm.saAgent.detach();
 245             throw ee;
 246         }
 247         return myvm;
 248     }
 249 
 250 
 251     VirtualMachineImpl(VirtualMachineManager mgr, int sequenceNumber)
 252         throws Exception {
 253         super(null);  // Can't use super(this)
 254         vm = this;
 255 
 256         this.sequenceNumber = sequenceNumber;
 257         this.vmmgr = mgr;
 258 
 259         /* Create ThreadGroup to be used by all threads servicing
 260          * this VM.
 261          */
 262         threadGroupForJDI = new ThreadGroup("JDI [" +
 263                                             this.hashCode() + "]");
 264 
 265         ((com.sun.tools.jdi.VirtualMachineManagerImpl)mgr).addVirtualMachine(this);
 266     }
 267 
 268     // we reflectively use newly spec'ed class because our ALT_BOOTDIR
 269     // is 1.4.2 and not 1.5.
 270     private static Class vmCannotBeModifiedExceptionClass = null;
 271     void throwNotReadOnlyException(String operation) {
 272         RuntimeException re = null;
 273         if (vmCannotBeModifiedExceptionClass == null) {
 274             try {
 275                 vmCannotBeModifiedExceptionClass = Class.forName("com.sun.jdi.VMCannotBeModifiedException");
 276             } catch (ClassNotFoundException cnfe) {
 277                 vmCannotBeModifiedExceptionClass = UnsupportedOperationException.class;
 278             }
 279         }
 280         try {
 281             re = (RuntimeException) vmCannotBeModifiedExceptionClass.newInstance();
 282         } catch (Exception exp) {
 283             re = new RuntimeException(exp.getMessage());
 284         }
 285         throw re;
 286     }
 287 
 288     public boolean equals(Object obj) {
 289         // Oh boy; big recursion troubles if we don't have this!
 290         // See MirrorImpl.equals
 291         return this == obj;
 292     }
 293 
 294     public int hashCode() {
 295         // big recursion if we don't have this. See MirrorImpl.hashCode
 296         return System.identityHashCode(this);
 297     }
 298 
 299     public List classesByName(String className) {
 300         String signature = JNITypeParser.typeNameToSignature(className);
 301         List list;
 302         if (!retrievedAllTypes) {
 303             retrieveAllClasses();
 304         }
 305         list = findReferenceTypes(signature);
 306         return Collections.unmodifiableList(list);
 307     }
 308 
 309     public List allClasses() {
 310         if (!retrievedAllTypes) {
 311             retrieveAllClasses();
 312         }
 313         ArrayList a;
 314         synchronized (this) {
 315             a = new ArrayList(typesBySignature);
 316         }
 317         return Collections.unmodifiableList(a);
 318     }
 319 
 320     // classes loaded by bootstrap loader
 321     List bootstrapClasses() {
 322         if (bootstrapClasses == null) {
 323             bootstrapClasses = new ArrayList();
 324             List all = allClasses();
 325             for (Iterator itr = all.iterator(); itr.hasNext();) {
 326                ReferenceType type = (ReferenceType) itr.next();
 327                if (type.classLoader() == null) {
 328                    bootstrapClasses.add(type);
 329                }
 330             }
 331         }
 332         return bootstrapClasses;
 333     }
 334 
 335     private synchronized List findReferenceTypes(String signature) {
 336         if (typesByID == null) {
 337             return new ArrayList(0);
 338         }
 339 
 340         // we haven't sorted types by signatures. But we can take
 341         // advantage of comparing symbols instead of name. In the worst
 342         // case, we will be comparing N addresses rather than N strings
 343         // where N being total no. of classes in allClasses() list.
 344 
 345         // The signature could be Lx/y/z; or [....
 346         // If it is Lx/y/z; the internal type name is x/y/x
 347         // for array klasses internal type name is same as
 348         // signature
 349         String typeName = null;
 350         if (signature.charAt(0) == 'L') {
 351             typeName = signature.substring(1, signature.length() - 1);
 352         } else {
 353             typeName = signature;
 354         }
 355 
 356         Symbol typeNameSym = saSymbolTable().probe(typeName);
 357         // if there is no symbol in VM, then we wouldn't have that type
 358         if (typeNameSym == null) {
 359             return new ArrayList(0);
 360         }
 361 
 362         Iterator iter = typesBySignature.iterator();
 363         List list = new ArrayList();
 364         while (iter.hasNext()) {
 365             // We have cached type name as symbol in reference type
 366             ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
 367             if (typeNameSym.equals(type.typeNameAsSymbol())) {
 368                 list.add(type);
 369             }
 370         }
 371         return list;
 372     }
 373 
 374     private void retrieveAllClasses() {
 375         final List saKlasses = new ArrayList();
 376         SystemDictionary.ClassVisitor visitor = new SystemDictionary.ClassVisitor() {
 377                 public void visit(Klass k) {
 378                     for (Klass l = k; l != null; l = l.arrayKlassOrNull()) {
 379                         // for non-array classes filter out un-prepared classes
 380                         // refer to 'allClasses' in share/back/VirtualMachineImpl.c
 381                         if (l instanceof ArrayKlass) {
 382                            saKlasses.add(l);
 383                         } else {
 384                            int status = l.getClassStatus();
 385                            if ((status & JVMDIClassStatus.PREPARED) != 0) {
 386                                saKlasses.add(l);
 387                            }
 388                         }
 389                     }
 390                 }
 391         };
 392 
 393         // refer to jvmtiGetLoadedClasses.cpp - getLoadedClasses in VM code.
 394 
 395         // classes from SystemDictionary
 396         saSystemDictionary.classesDo(visitor);
 397 
 398         // From SystemDictionary we do not get primitive single
 399         // dimensional array classes. add primitive single dimensional array
 400         // klasses from Universe.
 401         saVM.getUniverse().basicTypeClassesDo(visitor);
 402 
 403         // Hold lock during processing to improve performance
 404         // and to have safe check/set of retrievedAllTypes
 405         synchronized (this) {
 406             if (!retrievedAllTypes) {
 407                 // Number of classes
 408                 int count = saKlasses.size();
 409                 for (int ii = 0; ii < count; ii++) {
 410                     Klass kk = (Klass)saKlasses.get(ii);
 411                     ReferenceTypeImpl type = referenceType(kk);
 412                 }
 413                 retrievedAllTypes = true;
 414             }
 415         }
 416     }
 417 
 418     ReferenceTypeImpl referenceType(Klass kk) {
 419         ReferenceTypeImpl retType = null;
 420         synchronized (this) {
 421             if (typesByID != null) {
 422                 retType = (ReferenceTypeImpl)typesByID.get(kk);
 423             }
 424             if (retType == null) {
 425                 retType = addReferenceType(kk);
 426             }
 427         }
 428         return retType;
 429     }
 430 
 431     private void initReferenceTypes() {
 432         typesByID = new HashMap();
 433         typesBySignature = new ArrayList();
 434     }
 435 
 436     private synchronized ReferenceTypeImpl addReferenceType(Klass kk) {
 437         if (typesByID == null) {
 438             initReferenceTypes();
 439         }
 440         ReferenceTypeImpl newRefType = null;
 441         if (kk instanceof ObjArrayKlass || kk instanceof TypeArrayKlass) {
 442             newRefType = new ArrayTypeImpl(this, (ArrayKlass)kk);
 443         } else if (kk instanceof InstanceKlass) {
 444             if (kk.isInterface()) {
 445                 newRefType = new InterfaceTypeImpl(this, (InstanceKlass)kk);
 446             } else {
 447                 newRefType = new ClassTypeImpl(this, (InstanceKlass)kk);
 448             }
 449         } else {
 450             throw new RuntimeException("should not reach here");
 451         }
 452 
 453         typesByID.put(kk, newRefType);
 454         typesBySignature.add(newRefType);
 455         return newRefType;
 456     }
 457 
 458     ThreadGroup threadGroupForJDI() {
 459         return threadGroupForJDI;
 460     }
 461 
 462     public void redefineClasses(Map classToBytes) {
 463         throwNotReadOnlyException("VirtualMachineImpl.redefineClasses()");
 464     }
 465 
 466     private List getAllThreads() {
 467         if (allThreads == null) {
 468             allThreads = new ArrayList(10);  // Might be enough, might not be
 469             for (sun.jvm.hotspot.runtime.JavaThread thread =
 470                      saVM.getThreads().first(); thread != null;
 471                      thread = thread.next()) {
 472                 // refer to JvmtiEnv::GetAllThreads in jvmtiEnv.cpp.
 473                 // filter out the hidden-from-external-view threads.
 474                 if (thread.isHiddenFromExternalView() == false) {
 475                     ThreadReferenceImpl myThread = threadMirror(thread);
 476                     allThreads.add(myThread);
 477                 }
 478             }
 479         }
 480         return allThreads;
 481     }
 482 
 483     public List allThreads() { //fixme jjh
 484         return Collections.unmodifiableList(getAllThreads());
 485     }
 486 
 487     public void suspend() {
 488         throwNotReadOnlyException("VirtualMachineImpl.suspend()");
 489     }
 490 
 491     public void resume() {
 492         throwNotReadOnlyException("VirtualMachineImpl.resume()");
 493     }
 494 
 495     public List topLevelThreadGroups() { //fixme jjh
 496         // The doc for ThreadGroup says that The top-level thread group
 497         // is the only thread group whose parent is null.  This means there is
 498         // only one top level thread group.  There will be a thread in this
 499         // group so we will just find a thread whose threadgroup has no parent
 500         // and that will be it.
 501 
 502         if (topLevelGroups == null) {
 503             topLevelGroups = new ArrayList(1);
 504             Iterator myIt = getAllThreads().iterator();
 505             while (myIt.hasNext()) {
 506                 ThreadReferenceImpl myThread = (ThreadReferenceImpl)myIt.next();
 507                 ThreadGroupReference myGroup = myThread.threadGroup();
 508                 ThreadGroupReference myParent = myGroup.parent();
 509                 if (myGroup.parent() == null) {
 510                     topLevelGroups.add(myGroup);
 511                     break;
 512                 }
 513             }
 514         }
 515         return  Collections.unmodifiableList(topLevelGroups);
 516     }
 517 
 518     public EventQueue eventQueue() {
 519         throwNotReadOnlyException("VirtualMachine.eventQueue()");
 520         return null;
 521     }
 522 
 523     public EventRequestManager eventRequestManager() {
 524         throwNotReadOnlyException("VirtualMachineImpl.eventRequestManager()");
 525         return null;
 526     }
 527 
 528     public BooleanValue mirrorOf(boolean value) {
 529         return new BooleanValueImpl(this,value);
 530     }
 531 
 532     public ByteValue mirrorOf(byte value) {
 533         return new ByteValueImpl(this,value);
 534     }
 535 
 536     public CharValue mirrorOf(char value) {
 537         return new CharValueImpl(this,value);
 538     }
 539 
 540     public ShortValue mirrorOf(short value) {
 541         return new ShortValueImpl(this,value);
 542     }
 543 
 544     public IntegerValue mirrorOf(int value) {
 545         return new IntegerValueImpl(this,value);
 546     }
 547 
 548     public LongValue mirrorOf(long value) {
 549         return new LongValueImpl(this,value);
 550     }
 551 
 552     public FloatValue mirrorOf(float value) {
 553         return new FloatValueImpl(this,value);
 554     }
 555 
 556     public DoubleValue mirrorOf(double value) {
 557         return new DoubleValueImpl(this,value);
 558     }
 559 
 560     public StringReference mirrorOf(String value) {
 561         throwNotReadOnlyException("VirtualMachinestop.mirrorOf(String)");
 562         return null;
 563     }
 564 
 565     public VoidValue mirrorOfVoid() {
 566         if (voidVal == null) {
 567             voidVal = new VoidValueImpl(this);
 568         }
 569         return voidVal;
 570     }
 571 
 572 
 573     public Process process() {
 574         throwNotReadOnlyException("VirtualMachine.process");
 575         return null;
 576     }
 577 
 578     // dispose observer for Class re-use. refer to ConnectorImpl.
 579     private Observer disposeObserver;
 580 
 581     // ConnectorImpl loaded by a different class loader can not access it.
 582     // i.e., runtime package of <ConnectorImpl, L1> is not the same that of
 583     // <VirtualMachineImpl, L2> when L1 != L2. So, package private method
 584     // can be called reflectively after using setAccessible(true).
 585 
 586     void setDisposeObserver(Observer observer) {
 587        disposeObserver = observer;
 588     }
 589 
 590     private void notifyDispose() {
 591         if (Assert.ASSERTS_ENABLED) {
 592             Assert.that(disposeObserver != null, "null VM.dispose observer");
 593         }
 594         disposeObserver.update(null, null);
 595     }
 596 
 597     public void dispose() {
 598         saAgent.detach();
 599         notifyDispose();
 600     }
 601 
 602     public void exit(int exitCode) {
 603         throwNotReadOnlyException("VirtualMachine.exit(int)");
 604     }
 605 
 606     public boolean canBeModified() {
 607         return false;
 608     }
 609 
 610     public boolean canWatchFieldModification() {
 611         return false;
 612     }
 613 
 614     public boolean canWatchFieldAccess() {
 615         return false;
 616     }
 617 
 618     public boolean canGetBytecodes() {
 619         return true;
 620     }
 621 
 622     public boolean canGetSyntheticAttribute() {
 623         return true;
 624     }
 625 
 626     // FIXME: For now, all monitor capabilities are disabled
 627     public boolean canGetOwnedMonitorInfo() {
 628         return false;
 629     }
 630 
 631     public boolean canGetCurrentContendedMonitor() {
 632         return false;
 633     }
 634 
 635     public boolean canGetMonitorInfo() {
 636         return false;
 637     }
 638 
 639     // because this SA works only with 1.5 and update releases
 640     // this should always succeed unlike JVMDI/JDI.
 641     public boolean canGet1_5LanguageFeatures() {
 642         return true;
 643     }
 644 
 645     public boolean canUseInstanceFilters() {
 646         return false;
 647     }
 648 
 649     public boolean canRedefineClasses() {
 650         return false;
 651     }
 652 
 653     public boolean canAddMethod() {
 654         return false;
 655     }
 656 
 657     public boolean canUnrestrictedlyRedefineClasses() {
 658         return false;
 659     }
 660 
 661     public boolean canPopFrames() {
 662         return false;
 663     }
 664 
 665     public boolean canGetSourceDebugExtension() {
 666         // We can use InstanceKlass.getSourceDebugExtension only if
 667         // ClassFileParser parsed the info. But, ClassFileParser parses
 668         // SourceDebugExtension attribute only if corresponding JVMDI/TI
 669         // capability is set to true. Currently, vmStructs does not expose
 670         // JVMDI/TI capabilities and hence we conservatively assume false.
 671         return false;
 672     }
 673 
 674     public boolean canRequestVMDeathEvent() {
 675         return false;
 676     }
 677 
 678     // new method since 1.6
 679     public boolean canForceEarlyReturn() {
 680         return false;
 681     }
 682 
 683     // new method since 1.6
 684     public boolean canGetConstantPool() {
 685         return true;
 686     }
 687 
 688     // new method since 1.6
 689     public boolean canGetClassFileVersion() {
 690         return true;
 691     }
 692 
 693     // new method since 1.6.
 694     public boolean canGetMethodReturnValues() {
 695         return false;
 696     }
 697 
 698     // new method since 1.6
 699     // Real body will be supplied later.
 700     public boolean canGetInstanceInfo() {
 701         return true;
 702     }
 703 
 704     // new method since 1.6
 705     public boolean canUseSourceNameFilters() {
 706         return false;
 707     }
 708 
 709     // new method since 1.6.
 710     public boolean canRequestMonitorEvents() {
 711         return false;
 712     }
 713 
 714     // new method since 1.6.
 715     public boolean canGetMonitorFrameInfo() {
 716         return true;
 717     }
 718 
 719     // new method since 1.6
 720     // Real body will be supplied later.
 721     public long[] instanceCounts(List classes) {
 722         if (!canGetInstanceInfo()) {
 723             throw new UnsupportedOperationException(
 724                       "target does not support getting instances");
 725         }
 726 
 727         final long[] retValue = new long[classes.size()] ;
 728 
 729         final Klass [] klassArray = new Klass[classes.size()];
 730 
 731         boolean allAbstractClasses = true;
 732         for (int i=0; i < classes.size(); i++) {
 733             ReferenceTypeImpl rti = (ReferenceTypeImpl)classes.get(i);
 734             klassArray[i] = rti.ref();
 735             retValue[i]=0;
 736             if (!(rti.isAbstract() || ((ReferenceType)rti instanceof InterfaceType))) {
 737                 allAbstractClasses = false;
 738             }
 739         }
 740 
 741         if (allAbstractClasses) {
 742             return retValue;
 743         }
 744         final int size = classes.size();
 745         saObjectHeap.iterate(new DefaultHeapVisitor() {
 746                 public boolean doObj(Oop oop) {
 747                     for (int i=0; i < size; i++) {
 748                         if (klassArray[i].equals(oop.getKlass())) {
 749                             retValue[i]++;
 750                             break;
 751                         }
 752                     }
 753                                         return false;
 754                 }
 755             });
 756 
 757         return retValue;
 758     }
 759 
 760     private List getPath (String pathName) {
 761         String cp = saVM.getSystemProperty(pathName);
 762         String pathSep = saVM.getSystemProperty("path.separator");
 763         ArrayList al = new ArrayList();
 764         StringTokenizer st = new StringTokenizer(cp, pathSep);
 765         while (st.hasMoreTokens()) {
 766             al.add(st.nextToken());
 767         }
 768         al.trimToSize();
 769         return al;
 770     }
 771 
 772     public List classPath() {
 773         return getPath("java.class.path");
 774     }
 775 
 776     public List bootClassPath() {
 777         return getPath("sun.boot.class.path");
 778     }
 779 
 780     public String baseDirectory() {
 781         return saVM.getSystemProperty("user.dir");
 782     }
 783 
 784     public void setDefaultStratum(String stratum) {
 785         defaultStratum = stratum;
 786     }
 787 
 788     public String getDefaultStratum() {
 789         return defaultStratum;
 790     }
 791 
 792     public String description() {
 793         return java.text.MessageFormat.format(java.util.ResourceBundle.
 794                                               getBundle("com.sun.tools.jdi.resources.jdi").getString("version_format"),
 795                                               "" + vmmgr.majorInterfaceVersion(),
 796                                               "" + vmmgr.minorInterfaceVersion(),
 797                                               name());
 798     }
 799 
 800     public String version() {
 801         return saVM.getSystemProperty("java.version");
 802     }
 803 
 804     public String name() {
 805         StringBuffer sb = new StringBuffer();
 806         sb.append("JVM version ");
 807         sb.append(version());
 808         sb.append(" (");
 809         sb.append(saVM.getSystemProperty("java.vm.name"));
 810         sb.append(", ");
 811         sb.append(saVM.getSystemProperty("java.vm.info"));
 812         sb.append(")");
 813         return sb.toString();
 814     }
 815 
 816     // from interface Mirror
 817     public VirtualMachine virtualMachine() {
 818         return this;
 819     }
 820 
 821     public String toString() {
 822         return name();
 823     }
 824 
 825     public void setDebugTraceMode(int traceFlags) {
 826         // spec. says output is implementation dependent
 827         // and trace mode may be ignored. we ignore it :-)
 828     }
 829 
 830     // heap walking API
 831 
 832     // capability check
 833     public boolean canWalkHeap() {
 834         return true;
 835     }
 836 
 837     // return a list of all objects in heap
 838     public List/*<ObjectReference>*/ allObjects() {
 839         final List objects = new ArrayList(0);
 840         saObjectHeap.iterate(
 841             new DefaultHeapVisitor() {
 842                 public boolean doObj(Oop oop) {
 843                     objects.add(objectMirror(oop));
 844                                         return false;
 845                 }
 846             });
 847         return objects;
 848     }
 849 
 850     // equivalent to objectsByType(type, true)
 851     public List/*<ObjectReference>*/ objectsByType(ReferenceType type) {
 852         return objectsByType(type, true);
 853     }
 854 
 855     // returns objects of type exactly equal to given type
 856     private List/*<ObjectReference>*/ objectsByExactType(ReferenceType type) {
 857         final List objects = new ArrayList(0);
 858         final Klass givenKls = ((ReferenceTypeImpl)type).ref();
 859         saObjectHeap.iterate(new DefaultHeapVisitor() {
 860                 public boolean doObj(Oop oop) {
 861                     if (givenKls.equals(oop.getKlass())) {
 862                         objects.add(objectMirror(oop));
 863                     }
 864                         return false;
 865                 }
 866             });
 867         return objects;
 868     }
 869 
 870     // returns objects of given type as well as it's subtypes
 871     private List/*<ObjectReference>*/ objectsBySubType(ReferenceType type) {
 872         final List objects = new ArrayList(0);
 873         final ReferenceType givenType = type;
 874         saObjectHeap.iterate(new DefaultHeapVisitor() {
 875                 public boolean doObj(Oop oop) {
 876                     ReferenceTypeImpl curType = (ReferenceTypeImpl) referenceType(oop.getKlass());
 877                     if (curType.isAssignableTo(givenType)) {
 878                         objects.add(objectMirror(oop));
 879                     }
 880                         return false;
 881                 }
 882             });
 883         return objects;
 884     }
 885 
 886     // includeSubtypes - do you want to include subclass/subtype instances of given
 887     // ReferenceType or do we want objects of exact type only?
 888     public List/*<ObjectReference>*/ objectsByType(ReferenceType type, boolean includeSubtypes) {
 889         Klass kls = ((ReferenceTypeImpl)type).ref();
 890         if (kls instanceof InstanceKlass) {
 891             InstanceKlass ik = (InstanceKlass) kls;
 892             if (ik.isInterface()) {
 893                 if (ik.nofImplementors() == 0L) {
 894                     return new ArrayList(0);
 895                 }
 896             } else {
 897                 // if the Klass is final or if there are no subklasses loaded yet
 898                 if (ik.getAccessFlagsObj().isFinal() || ik.getSubklassKlass() == null) {
 899                     includeSubtypes = false;
 900                 }
 901             }
 902         } else {
 903             // no subtypes for primitive array types
 904             ArrayTypeImpl arrayType = (ArrayTypeImpl) type;
 905             try {
 906                 Type componentType = arrayType.componentType();
 907                 if (componentType instanceof PrimitiveType) {
 908                     includeSubtypes = false;
 909                 }
 910             } catch (ClassNotLoadedException cnle) {
 911                 // ignore. component type not yet loaded
 912             }
 913         }
 914 
 915         if (includeSubtypes) {
 916             return objectsBySubType(type);
 917         } else {
 918             return objectsByExactType(type);
 919         }
 920     }
 921 
 922     Type findBootType(String signature) throws ClassNotLoadedException {
 923         List types = allClasses();
 924         Iterator iter = types.iterator();
 925         while (iter.hasNext()) {
 926             ReferenceType type = (ReferenceType)iter.next();
 927             if ((type.classLoader() == null) &&
 928                 (type.signature().equals(signature))) {
 929                 return type;
 930             }
 931         }
 932         JNITypeParser parser = new JNITypeParser(signature);
 933         throw new ClassNotLoadedException(parser.typeName(),
 934                                          "Type " + parser.typeName() + " not loaded");
 935     }
 936 
 937     BooleanType theBooleanType() {
 938         if (theBooleanType == null) {
 939             synchronized(this) {
 940                 if (theBooleanType == null) {
 941                     theBooleanType = new BooleanTypeImpl(this);
 942                 }
 943             }
 944         }
 945         return theBooleanType;
 946     }
 947 
 948     ByteType theByteType() {
 949         if (theByteType == null) {
 950             synchronized(this) {
 951                 if (theByteType == null) {
 952                     theByteType = new ByteTypeImpl(this);
 953                 }
 954             }
 955         }
 956         return theByteType;
 957     }
 958 
 959     CharType theCharType() {
 960         if (theCharType == null) {
 961             synchronized(this) {
 962                 if (theCharType == null) {
 963                     theCharType = new CharTypeImpl(this);
 964                 }
 965             }
 966         }
 967         return theCharType;
 968     }
 969 
 970     ShortType theShortType() {
 971         if (theShortType == null) {
 972             synchronized(this) {
 973                 if (theShortType == null) {
 974                     theShortType = new ShortTypeImpl(this);
 975                 }
 976             }
 977         }
 978         return theShortType;
 979     }
 980 
 981     IntegerType theIntegerType() {
 982         if (theIntegerType == null) {
 983             synchronized(this) {
 984                 if (theIntegerType == null) {
 985                     theIntegerType = new IntegerTypeImpl(this);
 986                 }
 987             }
 988         }
 989         return theIntegerType;
 990     }
 991 
 992     LongType theLongType() {
 993         if (theLongType == null) {
 994             synchronized(this) {
 995                 if (theLongType == null) {
 996                     theLongType = new LongTypeImpl(this);
 997                 }
 998             }
 999         }
1000         return theLongType;
1001     }
1002 
1003     FloatType theFloatType() {
1004         if (theFloatType == null) {
1005             synchronized(this) {
1006                 if (theFloatType == null) {
1007                     theFloatType = new FloatTypeImpl(this);
1008                 }
1009             }
1010         }
1011         return theFloatType;
1012     }
1013 
1014     DoubleType theDoubleType() {
1015         if (theDoubleType == null) {
1016             synchronized(this) {
1017                 if (theDoubleType == null) {
1018                     theDoubleType = new DoubleTypeImpl(this);
1019                 }
1020             }
1021         }
1022         return theDoubleType;
1023     }
1024 
1025     VoidType theVoidType() {
1026         if (theVoidType == null) {
1027             synchronized(this) {
1028                 if (theVoidType == null) {
1029                     theVoidType = new VoidTypeImpl(this);
1030                 }
1031             }
1032         }
1033         return theVoidType;
1034     }
1035 
1036     PrimitiveType primitiveTypeMirror(char tag) {
1037         switch (tag) {
1038         case 'Z':
1039                 return theBooleanType();
1040         case 'B':
1041                 return theByteType();
1042         case 'C':
1043                 return theCharType();
1044         case 'S':
1045                 return theShortType();
1046         case 'I':
1047                 return theIntegerType();
1048         case 'J':
1049                 return theLongType();
1050         case 'F':
1051                 return theFloatType();
1052         case 'D':
1053                 return theDoubleType();
1054         default:
1055                 throw new IllegalArgumentException("Unrecognized primitive tag " + tag);
1056         }
1057     }
1058 
1059     private void processQueue() {
1060         Reference ref;
1061         while ((ref = referenceQueue.poll()) != null) {
1062             SoftObjectReference softRef = (SoftObjectReference)ref;
1063             removeObjectMirror(softRef);
1064         }
1065     }
1066 
1067     // Address value is used as uniqueID by ObjectReferenceImpl
1068     long getAddressValue(Oop obj) {
1069         return vm.saVM.getDebugger().getAddressValue(obj.getHandle());
1070     }
1071 
1072     synchronized ObjectReferenceImpl objectMirror(Oop key) {
1073 
1074         // Handle any queue elements that are not strongly reachable
1075         processQueue();
1076 
1077         if (key == null) {
1078             return null;
1079         }
1080         ObjectReferenceImpl object = null;
1081 
1082         /*
1083          * Attempt to retrieve an existing object object reference
1084          */
1085         SoftObjectReference ref = (SoftObjectReference)objectsByID.get(key);
1086         if (ref != null) {
1087             object = ref.object();
1088         }
1089 
1090         /*
1091          * If the object wasn't in the table, or it's soft reference was
1092          * cleared, create a new instance.
1093          */
1094         if (object == null) {
1095             if (key instanceof Instance) {
1096                 // look for well-known classes
1097                 Symbol className = key.getKlass().getName();
1098                 if (Assert.ASSERTS_ENABLED) {
1099                     Assert.that(className != null, "Null class name");
1100                 }
1101                 Instance inst = (Instance) key;
1102                 if (className.equals(javaLangString)) {
1103                     object = new StringReferenceImpl(this, inst);
1104                 } else if (className.equals(javaLangThread)) {
1105                     object = new ThreadReferenceImpl(this, inst);
1106                 } else if (className.equals(javaLangThreadGroup)) {
1107                     object = new ThreadGroupReferenceImpl(this, inst);
1108                 } else if (className.equals(javaLangClass)) {
1109                     object = new ClassObjectReferenceImpl(this, inst);
1110                 } else if (className.equals(javaLangClassLoader)) {
1111                     object = new ClassLoaderReferenceImpl(this, inst);
1112                 } else {
1113                     // not a well-known class. But the base class may be
1114                     // one of the known classes.
1115                     Klass kls = key.getKlass().getSuper();
1116                     while (kls != null) {
1117                        className = kls.getName();
1118                        // java.lang.Class and java.lang.String are final classes
1119                        if (className.equals(javaLangThread)) {
1120                           object = new ThreadReferenceImpl(this, inst);
1121                           break;
1122                        } else if(className.equals(javaLangThreadGroup)) {
1123                           object = new ThreadGroupReferenceImpl(this, inst);
1124                           break;
1125                        } else if (className.equals(javaLangClassLoader)) {
1126                           object = new ClassLoaderReferenceImpl(this, inst);
1127                           break;
1128                        }
1129                        kls = kls.getSuper();
1130                     }
1131 
1132                     if (object == null) {
1133                        // create generic object reference
1134                        object = new ObjectReferenceImpl(this, inst);
1135                     }
1136                 }
1137             } else if (key instanceof TypeArray) {
1138                 object = new ArrayReferenceImpl(this, (Array) key);
1139             } else if (key instanceof ObjArray) {
1140                 object = new ArrayReferenceImpl(this, (Array) key);
1141             } else {
1142                 throw new RuntimeException("unexpected object type " + key);
1143             }
1144             ref = new SoftObjectReference(key, object, referenceQueue);
1145 
1146             /*
1147              * If there was no previous entry in the table, we add one here
1148              * If the previous entry was cleared, we replace it here.
1149              */
1150             objectsByID.put(key, ref);
1151         } else {
1152             ref.incrementCount();
1153         }
1154 
1155         return object;
1156     }
1157 
1158     synchronized void removeObjectMirror(SoftObjectReference ref) {
1159         /*
1160          * This will remove the soft reference if it has not been
1161          * replaced in the cache.
1162          */
1163         objectsByID.remove(ref.key());
1164     }
1165 
1166     StringReferenceImpl stringMirror(Instance id) {
1167         return (StringReferenceImpl) objectMirror(id);
1168     }
1169 
1170     ArrayReferenceImpl arrayMirror(Array id) {
1171        return (ArrayReferenceImpl) objectMirror(id);
1172     }
1173 
1174     ThreadReferenceImpl threadMirror(Instance id) {
1175         return (ThreadReferenceImpl) objectMirror(id);
1176     }
1177 
1178     ThreadReferenceImpl threadMirror(JavaThread jt) {
1179         return (ThreadReferenceImpl) objectMirror(jt.getThreadObj());
1180     }
1181 
1182     ThreadGroupReferenceImpl threadGroupMirror(Instance id) {
1183         return (ThreadGroupReferenceImpl) objectMirror(id);
1184     }
1185 
1186     ClassLoaderReferenceImpl classLoaderMirror(Instance id) {
1187         return (ClassLoaderReferenceImpl) objectMirror(id);
1188     }
1189 
1190     ClassObjectReferenceImpl classObjectMirror(Instance id) {
1191         return (ClassObjectReferenceImpl) objectMirror(id);
1192     }
1193 
1194     // Use of soft refs and caching stuff here has to be re-examined.
1195     //  It might not make sense for JDI - SA.
1196     static private class SoftObjectReference extends SoftReference {
1197        int count;
1198        Object key;
1199 
1200        SoftObjectReference(Object key, ObjectReferenceImpl mirror,
1201                            ReferenceQueue queue) {
1202            super(mirror, queue);
1203            this.count = 1;
1204            this.key = key;
1205        }
1206 
1207        int count() {
1208            return count;
1209        }
1210 
1211        void incrementCount() {
1212            count++;
1213        }
1214 
1215        Object key() {
1216            return key;
1217        }
1218 
1219        ObjectReferenceImpl object() {
1220            return (ObjectReferenceImpl)get();
1221        }
1222    }
1223 }