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