History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/tools/jdi/VirtualMachineImpl.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/tools/jdi/VirtualMachineImpl.java+1442−0
@@ -0,0 +1,1442 @@
1+/*
2+ * Copyright (c) 1998, 2008, 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. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package com.sun.tools.jdi;
27+
28+import com.sun.jdi.*;
29+import com.sun.jdi.connect.spi.Connection;
30+import com.sun.jdi.request.EventRequestManager;
31+import com.sun.jdi.request.EventRequest;
32+import com.sun.jdi.request.BreakpointRequest;
33+import com.sun.jdi.event.EventQueue;
34+
35+import java.util.*;
36+import java.text.MessageFormat;
37+import java.lang.ref.ReferenceQueue;
38+import java.lang.ref.Reference;
39+import java.lang.ref.SoftReference;
40+import java.lang.ref.WeakReference;
41+
42+class VirtualMachineImpl extends MirrorImpl
43+ implements PathSearchingVirtualMachine, ThreadListener {
44+ // VM Level exported variables, these
45+ // are unique to a given vm
46+ public final int sizeofFieldRef;
47+ public final int sizeofMethodRef;
48+ public final int sizeofObjectRef;
49+ public final int sizeofClassRef;
50+ public final int sizeofFrameRef;
51+
52+ final int sequenceNumber;
53+
54+ private final TargetVM target;
55+ private final EventQueueImpl eventQueue;
56+ private final EventRequestManagerImpl internalEventRequestManager;
57+ private final EventRequestManagerImpl eventRequestManager;
58+ final VirtualMachineManagerImpl vmManager;
59+ private final ThreadGroup threadGroupForJDI;
60+
61+ // Allow direct access to this field so that that tracing code slows down
62+ // JDI as little as possible when not enabled.
63+ int traceFlags = TRACE_NONE;
64+
65+ static int TRACE_RAW_SENDS = 0x01000000;
66+ static int TRACE_RAW_RECEIVES = 0x02000000;
67+
68+ boolean traceReceives = false; // pre-compute because of frequency
69+
70+ // ReferenceType access - updated with class prepare and unload events
71+ // Protected by "synchronized(this)". "retrievedAllTypes" may be
72+ // tested unsynchronized (since once true, it stays true), but must
73+ // be set synchronously
74+ private Map<Long, ReferenceType> typesByID;
75+ private TreeSet<ReferenceType> typesBySignature;
76+ private boolean retrievedAllTypes = false;
77+
78+ // For other languages support
79+ private String defaultStratum = null;
80+
81+ // ObjectReference cache
82+ // "objectsByID" protected by "synchronized(this)".
83+ private final Map<Long, SoftObjectReference> objectsByID = new HashMap<Long, SoftObjectReference>();
84+ private final ReferenceQueue<ObjectReferenceImpl> referenceQueue = new ReferenceQueue<ObjectReferenceImpl>();
85+ static private final int DISPOSE_THRESHOLD = 50;
86+ private final List<SoftObjectReference> batchedDisposeRequests =
87+ Collections.synchronizedList(new ArrayList<SoftObjectReference>(DISPOSE_THRESHOLD + 10));
88+
89+ // These are cached once for the life of the VM
90+ private JDWP.VirtualMachine.Version versionInfo;
91+ private JDWP.VirtualMachine.ClassPaths pathInfo;
92+ private JDWP.VirtualMachine.Capabilities capabilities = null;
93+ private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew = null;
94+
95+ // Per-vm singletons for primitive types and for void.
96+ // singleton-ness protected by "synchronized(this)".
97+ private BooleanType theBooleanType;
98+ private ByteType theByteType;
99+ private CharType theCharType;
100+ private ShortType theShortType;
101+ private IntegerType theIntegerType;
102+ private LongType theLongType;
103+ private FloatType theFloatType;
104+ private DoubleType theDoubleType;
105+
106+ private VoidType theVoidType;
107+
108+ private VoidValue voidVal;
109+
110+ // Launched debuggee process
111+ private Process process;
112+
113+ // coordinates state changes and corresponding listener notifications
114+ private VMState state = new VMState(this);
115+
116+ private Object initMonitor = new Object();
117+ private boolean initComplete = false;
118+ private boolean shutdown = false;
119+
120+ private void notifyInitCompletion() {
121+ synchronized(initMonitor) {
122+ initComplete = true;
123+ initMonitor.notifyAll();
124+ }
125+ }
126+
127+ void waitInitCompletion() {
128+ synchronized(initMonitor) {
129+ while (!initComplete) {
130+ try {
131+ initMonitor.wait();
132+ } catch (InterruptedException e) {
133+ // ignore
134+ }
135+ }
136+ }
137+ }
138+
139+ VMState state() {
140+ return state;
141+ }
142+
143+ /*
144+ * ThreadListener implementation
145+ */
146+ public boolean threadResumable(ThreadAction action) {
147+ /*
148+ * If any thread is resumed, the VM is considered not suspended.
149+ * Just one thread is being resumed so pass it to thaw.
150+ */
151+ state.thaw(action.thread());
152+ return true;
153+ }
154+
155+ VirtualMachineImpl(VirtualMachineManager manager,
156+ Connection connection, Process process,
157+ int sequenceNumber) {
158+ super(null); // Can't use super(this)
159+ vm = this;
160+
161+ this.vmManager = (VirtualMachineManagerImpl)manager;
162+ this.process = process;
163+ this.sequenceNumber = sequenceNumber;
164+
165+ /* Create ThreadGroup to be used by all threads servicing
166+ * this VM.
167+ */
168+ threadGroupForJDI = new ThreadGroup(vmManager.mainGroupForJDI(),
169+ "JDI [" +
170+ this.hashCode() + "]");
171+
172+ /*
173+ * Set up a thread to communicate with the target VM over
174+ * the specified transport.
175+ */
176+ target = new TargetVM(this, connection);
177+
178+ /*
179+ * Set up a thread to handle events processed internally
180+ * the JDI implementation.
181+ */
182+ EventQueueImpl internalEventQueue = new EventQueueImpl(this, target);
183+ new InternalEventHandler(this, internalEventQueue);
184+ /*
185+ * Initialize client access to event setting and handling
186+ */
187+ eventQueue = new EventQueueImpl(this, target);
188+ eventRequestManager = new EventRequestManagerImpl(this);
189+
190+ target.start();
191+
192+ /*
193+ * Many ids are variably sized, depending on target VM.
194+ * Find out the sizes right away.
195+ */
196+ JDWP.VirtualMachine.IDSizes idSizes;
197+ try {
198+ idSizes = JDWP.VirtualMachine.IDSizes.process(vm);
199+ } catch (JDWPException exc) {
200+ throw exc.toJDIException();
201+ }
202+ sizeofFieldRef = idSizes.fieldIDSize;
203+ sizeofMethodRef = idSizes.methodIDSize;
204+ sizeofObjectRef = idSizes.objectIDSize;
205+ sizeofClassRef = idSizes.referenceTypeIDSize;
206+ sizeofFrameRef = idSizes.frameIDSize;
207+
208+ /**
209+ * Set up requests needed by internal event handler.
210+ * Make sure they are distinguished by creating them with
211+ * an internal event request manager.
212+ *
213+ * Warning: create events only with SUSPEND_NONE policy.
214+ * In the current implementation other policies will not
215+ * be handled correctly when the event comes in. (notfiySuspend()
216+ * will not be properly called, and if the event is combined
217+ * with external events in the same set, suspend policy is not
218+ * correctly determined for the internal vs. external event sets)
219+ */
220+ internalEventRequestManager = new EventRequestManagerImpl(this);
221+ EventRequest er = internalEventRequestManager.createClassPrepareRequest();
222+ er.setSuspendPolicy(EventRequest.SUSPEND_NONE);
223+ er.enable();
224+ er = internalEventRequestManager.createClassUnloadRequest();
225+ er.setSuspendPolicy(EventRequest.SUSPEND_NONE);
226+ er.enable();
227+
228+ /*
229+ * Tell other threads, notably TargetVM, that initialization
230+ * is complete.
231+ */
232+ notifyInitCompletion();
233+ }
234+
235+ EventRequestManagerImpl getInternalEventRequestManager() {
236+ return internalEventRequestManager;
237+ }
238+
239+ void validateVM() {
240+ /*
241+ * We no longer need to do this. The spec now says
242+ * that a VMDisconnected _may_ be thrown in these
243+ * cases, not that it _will_ be thrown.
244+ * So, to simplify things we will just let the
245+ * caller's of this method proceed with their business.
246+ * If the debuggee is disconnected, either because it
247+ * crashed or finished or something, or because the
248+ * debugger called exit() or dispose(), then if
249+ * we end up trying to communicate with the debuggee,
250+ * code in TargetVM will throw a VMDisconnectedException.
251+ * This means that if we can satisfy a request without
252+ * talking to the debuggee, (eg, with cached data) then
253+ * VMDisconnectedException will _not_ be thrown.
254+ * if (shutdown) {
255+ * throw new VMDisconnectedException();
256+ * }
257+ */
258+ }
259+
260+ public boolean equals(Object obj) {
261+ return this == obj;
262+ }
263+
264+ public int hashCode() {
265+ return System.identityHashCode(this);
266+ }
267+
268+ public List<ReferenceType> classesByName(String className) {
269+ validateVM();
270+ String signature = JNITypeParser.typeNameToSignature(className);
271+ List<ReferenceType> list;
272+ if (retrievedAllTypes) {
273+ list = findReferenceTypes(signature);
274+ } else {
275+ list = retrieveClassesBySignature(signature);
276+ }
277+ return Collections.unmodifiableList(list);
278+ }
279+
280+ public List<ReferenceType> allClasses() {
281+ validateVM();
282+
283+ if (!retrievedAllTypes) {
284+ retrieveAllClasses();
285+ }
286+ ArrayList<ReferenceType> a;
287+ synchronized (this) {
288+ a = new ArrayList<ReferenceType>(typesBySignature);
289+ }
290+ return Collections.unmodifiableList(a);
291+ }
292+
293+ public void
294+ redefineClasses(Map<? extends ReferenceType,byte[]> classToBytes)
295+ {
296+ int cnt = classToBytes.size();
297+ JDWP.VirtualMachine.RedefineClasses.ClassDef[] defs =
298+ new JDWP.VirtualMachine.RedefineClasses.ClassDef[cnt];
299+ validateVM();
300+ if (!canRedefineClasses()) {
301+ throw new UnsupportedOperationException();
302+ }
303+ Iterator it = classToBytes.entrySet().iterator();
304+ for (int i = 0; it.hasNext(); i++) {
305+ Map.Entry entry = (Map.Entry)it.next();
306+ ReferenceTypeImpl refType = (ReferenceTypeImpl)entry.getKey();
307+ validateMirror(refType);
308+ defs[i] = new JDWP.VirtualMachine.RedefineClasses
309+ .ClassDef(refType, (byte[])entry.getValue());
310+ }
311+
312+ // flush caches and disable caching until the next suspend
313+ vm.state().thaw();
314+
315+ try {
316+ JDWP.VirtualMachine.RedefineClasses.
317+ process(vm, defs);
318+ } catch (JDWPException exc) {
319+ switch (exc.errorCode()) {
320+ case JDWP.Error.INVALID_CLASS_FORMAT :
321+ throw new ClassFormatError(
322+ "class not in class file format");
323+ case JDWP.Error.CIRCULAR_CLASS_DEFINITION :
324+ throw new ClassCircularityError(
325+ "circularity has been detected while initializing a class");
326+ case JDWP.Error.FAILS_VERIFICATION :
327+ throw new VerifyError(
328+ "verifier detected internal inconsistency or security problem");
329+ case JDWP.Error.UNSUPPORTED_VERSION :
330+ throw new UnsupportedClassVersionError(
331+ "version numbers of class are not supported");
332+ case JDWP.Error.ADD_METHOD_NOT_IMPLEMENTED:
333+ throw new UnsupportedOperationException(
334+ "add method not implemented");
335+ case JDWP.Error.SCHEMA_CHANGE_NOT_IMPLEMENTED :
336+ throw new UnsupportedOperationException(
337+ "schema change not implemented");
338+ case JDWP.Error.HIERARCHY_CHANGE_NOT_IMPLEMENTED:
339+ throw new UnsupportedOperationException(
340+ "hierarchy change not implemented");
341+ case JDWP.Error.DELETE_METHOD_NOT_IMPLEMENTED :
342+ throw new UnsupportedOperationException(
343+ "delete method not implemented");
344+ case JDWP.Error.CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED:
345+ throw new UnsupportedOperationException(
346+ "changes to class modifiers not implemented");
347+ case JDWP.Error.METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED :
348+ throw new UnsupportedOperationException(
349+ "changes to method modifiers not implemented");
350+ case JDWP.Error.NAMES_DONT_MATCH :
351+ throw new NoClassDefFoundError(
352+ "class names do not match");
353+ default:
354+ throw exc.toJDIException();
355+ }
356+ }
357+
358+ // Delete any record of the breakpoints
359+ List<BreakpointRequest> toDelete = new ArrayList<BreakpointRequest>();
360+ EventRequestManager erm = eventRequestManager();
361+ it = erm.breakpointRequests().iterator();
362+ while (it.hasNext()) {
363+ BreakpointRequest req = (BreakpointRequest)it.next();
364+ if (classToBytes.containsKey(req.location().declaringType())) {
365+ toDelete.add(req);
366+ }
367+ }
368+ erm.deleteEventRequests(toDelete);
369+
370+ // Invalidate any information cached for the classes just redefined.
371+ it = classToBytes.keySet().iterator();
372+ while (it.hasNext()) {
373+ ReferenceTypeImpl rti = (ReferenceTypeImpl)it.next();
374+ rti.noticeRedefineClass();
375+ }
376+ }
377+
378+ public List<ThreadReference> allThreads() {
379+ validateVM();
380+ return state.allThreads();
381+ }
382+
383+ public List<ThreadGroupReference> topLevelThreadGroups() {
384+ validateVM();
385+ return state.topLevelThreadGroups();
386+ }
387+
388+ /*
389+ * Sends a command to the back end which is defined to do an
390+ * implicit vm-wide resume. The VM can no longer be considered
391+ * suspended, so certain cached data must be invalidated.
392+ */
393+ PacketStream sendResumingCommand(CommandSender sender) {
394+ return state.thawCommand(sender);
395+ }
396+
397+ /*
398+ * The VM has been suspended. Additional caching can be done
399+ * as long as there are no pending resumes.
400+ */
401+ void notifySuspend() {
402+ state.freeze();
403+ }
404+
405+ public void suspend() {
406+ validateVM();
407+ try {
408+ JDWP.VirtualMachine.Suspend.process(vm);
409+ } catch (JDWPException exc) {
410+ throw exc.toJDIException();
411+ }
412+ notifySuspend();
413+ }
414+
415+ public void resume() {
416+ validateVM();
417+ CommandSender sender =
418+ new CommandSender() {
419+ public PacketStream send() {
420+ return JDWP.VirtualMachine.Resume.enqueueCommand(vm);
421+ }
422+ };
423+ try {
424+ PacketStream stream = state.thawCommand(sender);
425+ JDWP.VirtualMachine.Resume.waitForReply(vm, stream);
426+ } catch (VMDisconnectedException exc) {
427+ /*
428+ * If the debugger makes a VMDeathRequest with SUSPEND_ALL,
429+ * then when it does an EventSet.resume after getting the
430+ * VMDeathEvent, the normal flow of events is that the
431+ * BE shuts down, but the waitForReply comes back ok. In this
432+ * case, the run loop in TargetVM that is waiting for a packet
433+ * gets an EOF because the socket closes. It generates a
434+ * VMDisconnectedEvent and everyone is happy.
435+ * However, sometimes, the BE gets shutdown before this
436+ * waitForReply completes. In this case, TargetVM.waitForReply
437+ * gets awakened with no reply and so gens a VMDisconnectedException
438+ * which is not what we want. It might be possible to fix this
439+ * in the BE, but it is ok to just ignore the VMDisconnectedException
440+ * here. This will allow the VMDisconnectedEvent to be generated
441+ * correctly. And, if the debugger should happen to make another
442+ * request, it will get a VMDisconnectedException at that time.
443+ */
444+ } catch (JDWPException exc) {
445+ switch (exc.errorCode()) {
446+ case JDWP.Error.VM_DEAD:
447+ return;
448+ default:
449+ throw exc.toJDIException();
450+ }
451+ }
452+ }
453+
454+ public EventQueue eventQueue() {
455+ /*
456+ * No VM validation here. We allow access to the event queue
457+ * after disconnection, so that there is access to the terminating
458+ * events.
459+ */
460+ return eventQueue;
461+ }
462+
463+ public EventRequestManager eventRequestManager() {
464+ validateVM();
465+ return eventRequestManager;
466+ }
467+
468+ EventRequestManagerImpl eventRequestManagerImpl() {
469+ return eventRequestManager;
470+ }
471+
472+ public BooleanValue mirrorOf(boolean value) {
473+ validateVM();
474+ return new BooleanValueImpl(this,value);
475+ }
476+
477+ public ByteValue mirrorOf(byte value) {
478+ validateVM();
479+ return new ByteValueImpl(this,value);
480+ }
481+
482+ public CharValue mirrorOf(char value) {
483+ validateVM();
484+ return new CharValueImpl(this,value);
485+ }
486+
487+ public ShortValue mirrorOf(short value) {
488+ validateVM();
489+ return new ShortValueImpl(this,value);
490+ }
491+
492+ public IntegerValue mirrorOf(int value) {
493+ validateVM();
494+ return new IntegerValueImpl(this,value);
495+ }
496+
497+ public LongValue mirrorOf(long value) {
498+ validateVM();
499+ return new LongValueImpl(this,value);
500+ }
501+
502+ public FloatValue mirrorOf(float value) {
503+ validateVM();
504+ return new FloatValueImpl(this,value);
505+ }
506+
507+ public DoubleValue mirrorOf(double value) {
508+ validateVM();
509+ return new DoubleValueImpl(this,value);
510+ }
511+
512+ public StringReference mirrorOf(String value) {
513+ validateVM();
514+ try {
515+ return (StringReference)JDWP.VirtualMachine.CreateString.
516+ process(vm, value).stringObject;
517+ } catch (JDWPException exc) {
518+ throw exc.toJDIException();
519+ }
520+ }
521+
522+ public VoidValue mirrorOfVoid() {
523+ if (voidVal == null) {
524+ voidVal = new VoidValueImpl(this);
525+ }
526+ return voidVal;
527+ }
528+
529+ public long[] instanceCounts(List<? extends ReferenceType> classes) {
530+ if (!canGetInstanceInfo()) {
531+ throw new UnsupportedOperationException(
532+ "target does not support getting instances");
533+ }
534+ long[] retValue ;
535+ ReferenceTypeImpl[] rtArray = new ReferenceTypeImpl[classes.size()];
536+ int ii = 0;
537+ for (ReferenceType rti: classes) {
538+ validateMirror(rti);
539+ rtArray[ii++] = (ReferenceTypeImpl)rti;
540+ }
541+ try {
542+ retValue = JDWP.VirtualMachine.InstanceCounts.
543+ process(vm, rtArray).counts;
544+ } catch (JDWPException exc) {
545+ throw exc.toJDIException();
546+ }
547+
548+ return retValue;
549+ }
550+
551+ public void dispose() {
552+ validateVM();
553+ shutdown = true;
554+ try {
555+ JDWP.VirtualMachine.Dispose.process(vm);
556+ } catch (JDWPException exc) {
557+ throw exc.toJDIException();
558+ }
559+ target.stopListening();
560+ }
561+
562+ public void exit(int exitCode) {
563+ validateVM();
564+ shutdown = true;
565+ try {
566+ JDWP.VirtualMachine.Exit.process(vm, exitCode);
567+ } catch (JDWPException exc) {
568+ throw exc.toJDIException();
569+ }
570+ target.stopListening();
571+ }
572+
573+ public Process process() {
574+ validateVM();
575+ return process;
576+ }
577+
578+ private JDWP.VirtualMachine.Version versionInfo() {
579+ try {
580+ if (versionInfo == null) {
581+ // Need not be synchronized since it is static information
582+ versionInfo = JDWP.VirtualMachine.Version.process(vm);
583+ }
584+ return versionInfo;
585+ } catch (JDWPException exc) {
586+ throw exc.toJDIException();
587+ }
588+ }
589+ public String description() {
590+ validateVM();
591+
592+ return MessageFormat.format(vmManager.getString("version_format"),
593+ "" + vmManager.majorInterfaceVersion(),
594+ "" + vmManager.minorInterfaceVersion(),
595+ versionInfo().description);
596+ }
597+
598+ public String version() {
599+ validateVM();
600+ return versionInfo().vmVersion;
601+ }
602+
603+ public String name() {
604+ validateVM();
605+ return versionInfo().vmName;
606+ }
607+
608+ public boolean canWatchFieldModification() {
609+ validateVM();
610+ return capabilities().canWatchFieldModification;
611+ }
612+ public boolean canWatchFieldAccess() {
613+ validateVM();
614+ return capabilities().canWatchFieldAccess;
615+ }
616+ public boolean canGetBytecodes() {
617+ validateVM();
618+ return capabilities().canGetBytecodes;
619+ }
620+ public boolean canGetSyntheticAttribute() {
621+ validateVM();
622+ return capabilities().canGetSyntheticAttribute;
623+ }
624+ public boolean canGetOwnedMonitorInfo() {
625+ validateVM();
626+ return capabilities().canGetOwnedMonitorInfo;
627+ }
628+ public boolean canGetCurrentContendedMonitor() {
629+ validateVM();
630+ return capabilities().canGetCurrentContendedMonitor;
631+ }
632+ public boolean canGetMonitorInfo() {
633+ validateVM();
634+ return capabilities().canGetMonitorInfo;
635+ }
636+
637+ private boolean hasNewCapabilities() {
638+ return versionInfo().jdwpMajor > 1 ||
639+ versionInfo().jdwpMinor >= 4;
640+ }
641+
642+ boolean canGet1_5LanguageFeatures() {
643+ return versionInfo().jdwpMajor > 1 ||
644+ versionInfo().jdwpMinor >= 5;
645+ }
646+
647+ public boolean canUseInstanceFilters() {
648+ validateVM();
649+ return hasNewCapabilities() &&
650+ capabilitiesNew().canUseInstanceFilters;
651+ }
652+ public boolean canRedefineClasses() {
653+ validateVM();
654+ return hasNewCapabilities() &&
655+ capabilitiesNew().canRedefineClasses;
656+ }
657+ public boolean canAddMethod() {
658+ validateVM();
659+ return hasNewCapabilities() &&
660+ capabilitiesNew().canAddMethod;
661+ }
662+ public boolean canUnrestrictedlyRedefineClasses() {
663+ validateVM();
664+ return hasNewCapabilities() &&
665+ capabilitiesNew().canUnrestrictedlyRedefineClasses;
666+ }
667+ public boolean canPopFrames() {
668+ validateVM();
669+ return hasNewCapabilities() &&
670+ capabilitiesNew().canPopFrames;
671+ }
672+ public boolean canGetMethodReturnValues() {
673+ return versionInfo().jdwpMajor > 1 ||
674+ versionInfo().jdwpMinor >= 6;
675+ }
676+ public boolean canGetInstanceInfo() {
677+ if (versionInfo().jdwpMajor < 1 ||
678+ versionInfo().jdwpMinor < 6) {
679+ return false;
680+ }
681+ validateVM();
682+ return hasNewCapabilities() &&
683+ capabilitiesNew().canGetInstanceInfo;
684+ }
685+ public boolean canUseSourceNameFilters() {
686+ if (versionInfo().jdwpMajor < 1 ||
687+ versionInfo().jdwpMinor < 6) {
688+ return false;
689+ }
690+ return true;
691+ }
692+ public boolean canForceEarlyReturn() {
693+ validateVM();
694+ return hasNewCapabilities() &&
695+ capabilitiesNew().canForceEarlyReturn;
696+ }
697+ public boolean canBeModified() {
698+ return true;
699+ }
700+ public boolean canGetSourceDebugExtension() {
701+ validateVM();
702+ return hasNewCapabilities() &&
703+ capabilitiesNew().canGetSourceDebugExtension;
704+ }
705+ public boolean canGetClassFileVersion() {
706+ if ( versionInfo().jdwpMajor < 1 &&
707+ versionInfo().jdwpMinor < 6) {
708+ return false;
709+ } else {
710+ return true;
711+ }
712+ }
713+ public boolean canGetConstantPool() {
714+ validateVM();
715+ return hasNewCapabilities() &&
716+ capabilitiesNew().canGetConstantPool;
717+ }
718+ public boolean canRequestVMDeathEvent() {
719+ validateVM();
720+ return hasNewCapabilities() &&
721+ capabilitiesNew().canRequestVMDeathEvent;
722+ }
723+ public boolean canRequestMonitorEvents() {
724+ validateVM();
725+ return hasNewCapabilities() &&
726+ capabilitiesNew().canRequestMonitorEvents;
727+ }
728+ public boolean canGetMonitorFrameInfo() {
729+ validateVM();
730+ return hasNewCapabilities() &&
731+ capabilitiesNew().canGetMonitorFrameInfo;
732+ }
733+
734+ public void setDebugTraceMode(int traceFlags) {
735+ validateVM();
736+ this.traceFlags = traceFlags;
737+ this.traceReceives = (traceFlags & TRACE_RECEIVES) != 0;
738+ }
739+
740+ void printTrace(String string) {
741+ System.err.println("[JDI: " + string + "]");
742+ }
743+
744+ void printReceiveTrace(int depth, String string) {
745+ StringBuffer sb = new StringBuffer("Receiving:");
746+ for (int i = depth; i > 0; --i) {
747+ sb.append(" ");
748+ }
749+ sb.append(string);
750+ printTrace(sb.toString());
751+ }
752+
753+ private synchronized ReferenceTypeImpl addReferenceType(long id,
754+ int tag,
755+ String signature) {
756+ if (typesByID == null) {
757+ initReferenceTypes();
758+ }
759+ ReferenceTypeImpl type = null;
760+ switch(tag) {
761+ case JDWP.TypeTag.CLASS:
762+ type = new ClassTypeImpl(vm, id);
763+ break;
764+ case JDWP.TypeTag.INTERFACE:
765+ type = new InterfaceTypeImpl(vm, id);
766+ break;
767+ case JDWP.TypeTag.ARRAY:
768+ type = new ArrayTypeImpl(vm, id);
769+ break;
770+ default:
771+ throw new InternalException("Invalid reference type tag");
772+ }
773+
774+ /*
775+ * If a signature was specified, make sure to set it ASAP, to
776+ * prevent any needless JDWP command to retrieve it. (for example,
777+ * typesBySignature.add needs the signature, to maintain proper
778+ * ordering.
779+ */
780+ if (signature != null) {
781+ type.setSignature(signature);
782+ }
783+
784+ typesByID.put(new Long(id), type);
785+ typesBySignature.add(type);
786+
787+ if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
788+ vm.printTrace("Caching new ReferenceType, sig=" + signature +
789+ ", id=" + id);
790+ }
791+
792+ return type;
793+ }
794+
795+ synchronized void removeReferenceType(String signature) {
796+ if (typesByID == null) {
797+ return;
798+ }
799+ /*
800+ * There can be multiple classes with the same name. Since
801+ * we can't differentiate here, we first remove all
802+ * matching classes from our cache...
803+ */
804+ Iterator iter = typesBySignature.iterator();
805+ int matches = 0;
806+ while (iter.hasNext()) {
807+ ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
808+ int comp = signature.compareTo(type.signature());
809+ if (comp == 0) {
810+ matches++;
811+ iter.remove();
812+ typesByID.remove(new Long(type.ref()));
813+ if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
814+ vm.printTrace("Uncaching ReferenceType, sig=" + signature +
815+ ", id=" + type.ref());
816+ }
817+/* fix for 4359077 , don't break out. list is no longer sorted
818+ in the order we think
819+ */
820+ }
821+ }
822+
823+ /*
824+ * ...and if there was more than one, re-retrieve the classes
825+ * with that name
826+ */
827+ if (matches > 1) {
828+ retrieveClassesBySignature(signature);
829+ }
830+ }
831+
832+ private synchronized List<ReferenceType> findReferenceTypes(String signature) {
833+ if (typesByID == null) {
834+ return new ArrayList<ReferenceType>(0);
835+ }
836+ Iterator iter = typesBySignature.iterator();
837+ List<ReferenceType> list = new ArrayList<ReferenceType>();
838+ while (iter.hasNext()) {
839+ ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
840+ int comp = signature.compareTo(type.signature());
841+ if (comp == 0) {
842+ list.add(type);
843+/* fix for 4359077 , don't break out. list is no longer sorted
844+ in the order we think
845+ */
846+ }
847+ }
848+ return list;
849+ }
850+
851+ private void initReferenceTypes() {
852+ typesByID = new HashMap<Long, ReferenceType>(300);
853+ typesBySignature = new TreeSet<ReferenceType>();
854+ }
855+
856+ ReferenceTypeImpl referenceType(long ref, byte tag) {
857+ return referenceType(ref, tag, null);
858+ }
859+
860+ ClassTypeImpl classType(long ref) {
861+ return (ClassTypeImpl)referenceType(ref, JDWP.TypeTag.CLASS, null);
862+ }
863+
864+ InterfaceTypeImpl interfaceType(long ref) {
865+ return (InterfaceTypeImpl)referenceType(ref, JDWP.TypeTag.INTERFACE, null);
866+ }
867+
868+ ArrayTypeImpl arrayType(long ref) {
869+ return (ArrayTypeImpl)referenceType(ref, JDWP.TypeTag.ARRAY, null);
870+ }
871+
872+ ReferenceTypeImpl referenceType(long id, int tag,
873+ String signature) {
874+ if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
875+ StringBuffer sb = new StringBuffer();
876+ sb.append("Looking up ");
877+ if (tag == JDWP.TypeTag.CLASS) {
878+ sb.append("Class");
879+ } else if (tag == JDWP.TypeTag.INTERFACE) {
880+ sb.append("Interface");
881+ } else if (tag == JDWP.TypeTag.ARRAY) {
882+ sb.append("ArrayType");
883+ } else {
884+ sb.append("UNKNOWN TAG: " + tag);
885+ }
886+ if (signature != null) {
887+ sb.append(", signature='" + signature + "'");
888+ }
889+ sb.append(", id=" + id);
890+ vm.printTrace(sb.toString());
891+ }
892+ if (id == 0) {
893+ return null;
894+ } else {
895+ ReferenceTypeImpl retType = null;
896+ synchronized (this) {
897+ if (typesByID != null) {
898+ retType = (ReferenceTypeImpl)typesByID.get(new Long(id));
899+ }
900+ if (retType == null) {
901+ retType = addReferenceType(id, tag, signature);
902+ }
903+ }
904+ return retType;
905+ }
906+ }
907+
908+ private JDWP.VirtualMachine.Capabilities capabilities() {
909+ if (capabilities == null) {
910+ try {
911+ capabilities = JDWP.VirtualMachine
912+ .Capabilities.process(vm);
913+ } catch (JDWPException exc) {
914+ throw exc.toJDIException();
915+ }
916+ }
917+ return capabilities;
918+ }
919+
920+ private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew() {
921+ if (capabilitiesNew == null) {
922+ try {
923+ capabilitiesNew = JDWP.VirtualMachine
924+ .CapabilitiesNew.process(vm);
925+ } catch (JDWPException exc) {
926+ throw exc.toJDIException();
927+ }
928+ }
929+ return capabilitiesNew;
930+ }
931+
932+ private List<ReferenceType> retrieveClassesBySignature(String signature) {
933+ if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
934+ vm.printTrace("Retrieving matching ReferenceTypes, sig=" + signature);
935+ }
936+ JDWP.VirtualMachine.ClassesBySignature.ClassInfo[] cinfos;
937+ try {
938+ cinfos = JDWP.VirtualMachine.ClassesBySignature.
939+ process(vm, signature).classes;
940+ } catch (JDWPException exc) {
941+ throw exc.toJDIException();
942+ }
943+
944+ int count = cinfos.length;
945+ List<ReferenceType> list = new ArrayList<ReferenceType>(count);
946+
947+ // Hold lock during processing to improve performance
948+ synchronized (this) {
949+ for (int i = 0; i < count; i++) {
950+ JDWP.VirtualMachine.ClassesBySignature.ClassInfo ci =
951+ cinfos[i];
952+ ReferenceTypeImpl type = referenceType(ci.typeID,
953+ ci.refTypeTag,
954+ signature);
955+ type.setStatus(ci.status);
956+ list.add(type);
957+ }
958+ }
959+ return list;
960+ }
961+
962+ private void retrieveAllClasses1_4() {
963+ JDWP.VirtualMachine.AllClasses.ClassInfo[] cinfos;
964+ try {
965+ cinfos = JDWP.VirtualMachine.AllClasses.process(vm).classes;
966+ } catch (JDWPException exc) {
967+ throw exc.toJDIException();
968+ }
969+
970+ // Hold lock during processing to improve performance
971+ // and to have safe check/set of retrievedAllTypes
972+ synchronized (this) {
973+ if (!retrievedAllTypes) {
974+ // Number of classes
975+ int count = cinfos.length;
976+ for (int i=0; i<count; i++) {
977+ JDWP.VirtualMachine.AllClasses.ClassInfo ci =
978+ cinfos[i];
979+ ReferenceTypeImpl type = referenceType(ci.typeID,
980+ ci.refTypeTag,
981+ ci.signature);
982+ type.setStatus(ci.status);
983+ }
984+ retrievedAllTypes = true;
985+ }
986+ }
987+ }
988+
989+ private void retrieveAllClasses() {
990+ if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
991+ vm.printTrace("Retrieving all ReferenceTypes");
992+ }
993+
994+ if (!vm.canGet1_5LanguageFeatures()) {
995+ retrieveAllClasses1_4();
996+ return;
997+ }
998+
999+ /*
1000+ * To save time (assuming the caller will be
1001+ * using then) we will get the generic sigs too.
1002+ */
1003+
1004+ JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo[] cinfos;
1005+ try {
1006+ cinfos = JDWP.VirtualMachine.AllClassesWithGeneric.process(vm).classes;
1007+ } catch (JDWPException exc) {
1008+ throw exc.toJDIException();
1009+ }
1010+
1011+ // Hold lock during processing to improve performance
1012+ // and to have safe check/set of retrievedAllTypes
1013+ synchronized (this) {
1014+ if (!retrievedAllTypes) {
1015+ // Number of classes
1016+ int count = cinfos.length;
1017+ for (int i=0; i<count; i++) {
1018+ JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo ci =
1019+ cinfos[i];
1020+ ReferenceTypeImpl type = referenceType(ci.typeID,
1021+ ci.refTypeTag,
1022+ ci.signature);
1023+ type.setGenericSignature(ci.genericSignature);
1024+ type.setStatus(ci.status);
1025+ }
1026+ retrievedAllTypes = true;
1027+ }
1028+ }
1029+ }
1030+
1031+ void sendToTarget(Packet packet) {
1032+ target.send(packet);
1033+ }
1034+
1035+ void waitForTargetReply(Packet packet) {
1036+ target.waitForReply(packet);
1037+ /*
1038+ * If any object disposes have been batched up, send them now.
1039+ */
1040+ processBatchedDisposes();
1041+ }
1042+
1043+ Type findBootType(String signature) throws ClassNotLoadedException {
1044+ List types = allClasses();
1045+ Iterator iter = types.iterator();
1046+ while (iter.hasNext()) {
1047+ ReferenceType type = (ReferenceType)iter.next();
1048+ if ((type.classLoader() == null) &&
1049+ (type.signature().equals(signature))) {
1050+ return type;
1051+ }
1052+ }
1053+ JNITypeParser parser = new JNITypeParser(signature);
1054+ throw new ClassNotLoadedException(parser.typeName(),
1055+ "Type " + parser.typeName() + " not loaded");
1056+ }
1057+
1058+ BooleanType theBooleanType() {
1059+ if (theBooleanType == null) {
1060+ synchronized(this) {
1061+ if (theBooleanType == null) {
1062+ theBooleanType = new BooleanTypeImpl(this);
1063+ }
1064+ }
1065+ }
1066+ return theBooleanType;
1067+ }
1068+
1069+ ByteType theByteType() {
1070+ if (theByteType == null) {
1071+ synchronized(this) {
1072+ if (theByteType == null) {
1073+ theByteType = new ByteTypeImpl(this);
1074+ }
1075+ }
1076+ }
1077+ return theByteType;
1078+ }
1079+
1080+ CharType theCharType() {
1081+ if (theCharType == null) {
1082+ synchronized(this) {
1083+ if (theCharType == null) {
1084+ theCharType = new CharTypeImpl(this);
1085+ }
1086+ }
1087+ }
1088+ return theCharType;
1089+ }
1090+
1091+ ShortType theShortType() {
1092+ if (theShortType == null) {
1093+ synchronized(this) {
1094+ if (theShortType == null) {
1095+ theShortType = new ShortTypeImpl(this);
1096+ }
1097+ }
1098+ }
1099+ return theShortType;
1100+ }
1101+
1102+ IntegerType theIntegerType() {
1103+ if (theIntegerType == null) {
1104+ synchronized(this) {
1105+ if (theIntegerType == null) {
1106+ theIntegerType = new IntegerTypeImpl(this);
1107+ }
1108+ }
1109+ }
1110+ return theIntegerType;
1111+ }
1112+
1113+ LongType theLongType() {
1114+ if (theLongType == null) {
1115+ synchronized(this) {
1116+ if (theLongType == null) {
1117+ theLongType = new LongTypeImpl(this);
1118+ }
1119+ }
1120+ }
1121+ return theLongType;
1122+ }
1123+
1124+ FloatType theFloatType() {
1125+ if (theFloatType == null) {
1126+ synchronized(this) {
1127+ if (theFloatType == null) {
1128+ theFloatType = new FloatTypeImpl(this);
1129+ }
1130+ }
1131+ }
1132+ return theFloatType;
1133+ }
1134+
1135+ DoubleType theDoubleType() {
1136+ if (theDoubleType == null) {
1137+ synchronized(this) {
1138+ if (theDoubleType == null) {
1139+ theDoubleType = new DoubleTypeImpl(this);
1140+ }
1141+ }
1142+ }
1143+ return theDoubleType;
1144+ }
1145+
1146+ VoidType theVoidType() {
1147+ if (theVoidType == null) {
1148+ synchronized(this) {
1149+ if (theVoidType == null) {
1150+ theVoidType = new VoidTypeImpl(this);
1151+ }
1152+ }
1153+ }
1154+ return theVoidType;
1155+ }
1156+
1157+ PrimitiveType primitiveTypeMirror(byte tag) {
1158+ switch (tag) {
1159+ case JDWP.Tag.BOOLEAN:
1160+ return theBooleanType();
1161+ case JDWP.Tag.BYTE:
1162+ return theByteType();
1163+ case JDWP.Tag.CHAR:
1164+ return theCharType();
1165+ case JDWP.Tag.SHORT:
1166+ return theShortType();
1167+ case JDWP.Tag.INT:
1168+ return theIntegerType();
1169+ case JDWP.Tag.LONG:
1170+ return theLongType();
1171+ case JDWP.Tag.FLOAT:
1172+ return theFloatType();
1173+ case JDWP.Tag.DOUBLE:
1174+ return theDoubleType();
1175+ default:
1176+ throw new IllegalArgumentException("Unrecognized primitive tag " + tag);
1177+ }
1178+ }
1179+
1180+ private void processBatchedDisposes() {
1181+ if (shutdown) {
1182+ return;
1183+ }
1184+
1185+ JDWP.VirtualMachine.DisposeObjects.Request[] requests = null;
1186+ synchronized(batchedDisposeRequests) {
1187+ int size = batchedDisposeRequests.size();
1188+ if (size >= DISPOSE_THRESHOLD) {
1189+ if ((traceFlags & TRACE_OBJREFS) != 0) {
1190+ printTrace("Dispose threashold reached. Will dispose "
1191+ + size + " object references...");
1192+ }
1193+ requests = new JDWP.VirtualMachine.DisposeObjects.Request[size];
1194+ for (int i = 0; i < requests.length; i++) {
1195+ SoftObjectReference ref = batchedDisposeRequests.get(i);
1196+ if ((traceFlags & TRACE_OBJREFS) != 0) {
1197+ printTrace("Disposing object " + ref.key().longValue() +
1198+ " (ref count = " + ref.count() + ")");
1199+ }
1200+
1201+ // This is kludgy. We temporarily re-create an object
1202+ // reference so that we can correctly pass its id to the
1203+ // JDWP command.
1204+ requests[i] =
1205+ new JDWP.VirtualMachine.DisposeObjects.Request(
1206+ new ObjectReferenceImpl(this, ref.key().longValue()),
1207+ ref.count());
1208+ }
1209+ batchedDisposeRequests.clear();
1210+ }
1211+ }
1212+ if (requests != null) {
1213+ try {
1214+ JDWP.VirtualMachine.DisposeObjects.process(vm, requests);
1215+ } catch (JDWPException exc) {
1216+ throw exc.toJDIException();
1217+ }
1218+ }
1219+ }
1220+
1221+ private void batchForDispose(SoftObjectReference ref) {
1222+ if ((traceFlags & TRACE_OBJREFS) != 0) {
1223+ printTrace("Batching object " + ref.key().longValue() +
1224+ " for dispose (ref count = " + ref.count() + ")");
1225+ }
1226+ batchedDisposeRequests.add(ref);
1227+ }
1228+
1229+ private void processQueue() {
1230+ Reference ref;
1231+ //if ((traceFlags & TRACE_OBJREFS) != 0) {
1232+ // printTrace("Checking for softly reachable objects");
1233+ //}
1234+ while ((ref = referenceQueue.poll()) != null) {
1235+ SoftObjectReference softRef = (SoftObjectReference)ref;
1236+ removeObjectMirror(softRef);
1237+ batchForDispose(softRef);
1238+ }
1239+ }
1240+
1241+ synchronized ObjectReferenceImpl objectMirror(long id, int tag) {
1242+
1243+ // Handle any queue elements that are not strongly reachable
1244+ processQueue();
1245+
1246+ if (id == 0) {
1247+ return null;
1248+ }
1249+ ObjectReferenceImpl object = null;
1250+ Long key = new Long(id);
1251+
1252+ /*
1253+ * Attempt to retrieve an existing object object reference
1254+ */
1255+ SoftObjectReference ref = objectsByID.get(key);
1256+ if (ref != null) {
1257+ object = ref.object();
1258+ }
1259+
1260+ /*
1261+ * If the object wasn't in the table, or it's soft reference was
1262+ * cleared, create a new instance.
1263+ */
1264+ if (object == null) {
1265+ switch (tag) {
1266+ case JDWP.Tag.OBJECT:
1267+ object = new ObjectReferenceImpl(vm, id);
1268+ break;
1269+ case JDWP.Tag.STRING:
1270+ object = new StringReferenceImpl(vm, id);
1271+ break;
1272+ case JDWP.Tag.ARRAY:
1273+ object = new ArrayReferenceImpl(vm, id);
1274+ break;
1275+ case JDWP.Tag.THREAD:
1276+ ThreadReferenceImpl thread =
1277+ new ThreadReferenceImpl(vm, id);
1278+ thread.addListener(this);
1279+ object = thread;
1280+ break;
1281+ case JDWP.Tag.THREAD_GROUP:
1282+ object = new ThreadGroupReferenceImpl(vm, id);
1283+ break;
1284+ case JDWP.Tag.CLASS_LOADER:
1285+ object = new ClassLoaderReferenceImpl(vm, id);
1286+ break;
1287+ case JDWP.Tag.CLASS_OBJECT:
1288+ object = new ClassObjectReferenceImpl(vm, id);
1289+ break;
1290+ default:
1291+ throw new IllegalArgumentException("Invalid object tag: " + tag);
1292+ }
1293+ ref = new SoftObjectReference(key, object, referenceQueue);
1294+
1295+ /*
1296+ * If there was no previous entry in the table, we add one here
1297+ * If the previous entry was cleared, we replace it here.
1298+ */
1299+ objectsByID.put(key, ref);
1300+ if ((traceFlags & TRACE_OBJREFS) != 0) {
1301+ printTrace("Creating new " +
1302+ object.getClass().getName() + " (id = " + id + ")");
1303+ }
1304+ } else {
1305+ ref.incrementCount();
1306+ }
1307+
1308+ return object;
1309+ }
1310+
1311+ synchronized void removeObjectMirror(ObjectReferenceImpl object) {
1312+
1313+ // Handle any queue elements that are not strongly reachable
1314+ processQueue();
1315+
1316+ SoftObjectReference ref = objectsByID.remove(new Long(object.ref()));
1317+ if (ref != null) {
1318+ batchForDispose(ref);
1319+ } else {
1320+ /*
1321+ * If there's a live ObjectReference about, it better be part
1322+ * of the cache.
1323+ */
1324+ throw new InternalException("ObjectReference " + object.ref() +
1325+ " not found in object cache");
1326+ }
1327+ }
1328+
1329+ synchronized void removeObjectMirror(SoftObjectReference ref) {
1330+ /*
1331+ * This will remove the soft reference if it has not been
1332+ * replaced in the cache.
1333+ */
1334+ objectsByID.remove(ref.key());
1335+ }
1336+
1337+ ObjectReferenceImpl objectMirror(long id) {
1338+ return objectMirror(id, JDWP.Tag.OBJECT);
1339+ }
1340+
1341+ StringReferenceImpl stringMirror(long id) {
1342+ return (StringReferenceImpl)objectMirror(id, JDWP.Tag.STRING);
1343+ }
1344+
1345+ ArrayReferenceImpl arrayMirror(long id) {
1346+ return (ArrayReferenceImpl)objectMirror(id, JDWP.Tag.ARRAY);
1347+ }
1348+
1349+ ThreadReferenceImpl threadMirror(long id) {
1350+ return (ThreadReferenceImpl)objectMirror(id, JDWP.Tag.THREAD);
1351+ }
1352+
1353+ ThreadGroupReferenceImpl threadGroupMirror(long id) {
1354+ return (ThreadGroupReferenceImpl)objectMirror(id,
1355+ JDWP.Tag.THREAD_GROUP);
1356+ }
1357+
1358+ ClassLoaderReferenceImpl classLoaderMirror(long id) {
1359+ return (ClassLoaderReferenceImpl)objectMirror(id,
1360+ JDWP.Tag.CLASS_LOADER);
1361+ }
1362+
1363+ ClassObjectReferenceImpl classObjectMirror(long id) {
1364+ return (ClassObjectReferenceImpl)objectMirror(id,
1365+ JDWP.Tag.CLASS_OBJECT);
1366+ }
1367+
1368+ /*
1369+ * Implementation of PathSearchingVirtualMachine
1370+ */
1371+ private JDWP.VirtualMachine.ClassPaths getClasspath() {
1372+ if (pathInfo == null) {
1373+ try {
1374+ pathInfo = JDWP.VirtualMachine.ClassPaths.process(vm);
1375+ } catch (JDWPException exc) {
1376+ throw exc.toJDIException();
1377+ }
1378+ }
1379+ return pathInfo;
1380+ }
1381+
1382+ public List<String> classPath() {
1383+ return Arrays.asList(getClasspath().classpaths);
1384+ }
1385+
1386+ public List<String> bootClassPath() {
1387+ return Arrays.asList(getClasspath().bootclasspaths);
1388+ }
1389+
1390+ public String baseDirectory() {
1391+ return getClasspath().baseDir;
1392+ }
1393+
1394+ public void setDefaultStratum(String stratum) {
1395+ defaultStratum = stratum;
1396+ if (stratum == null) {
1397+ stratum = "";
1398+ }
1399+ try {
1400+ JDWP.VirtualMachine.SetDefaultStratum.process(vm,
1401+ stratum);
1402+ } catch (JDWPException exc) {
1403+ throw exc.toJDIException();
1404+ }
1405+ }
1406+
1407+ public String getDefaultStratum() {
1408+ return defaultStratum;
1409+ }
1410+
1411+ ThreadGroup threadGroupForJDI() {
1412+ return threadGroupForJDI;
1413+ }
1414+
1415+ static private class SoftObjectReference extends SoftReference<ObjectReferenceImpl> {
1416+ int count;
1417+ Long key;
1418+
1419+ SoftObjectReference(Long key, ObjectReferenceImpl mirror,
1420+ ReferenceQueue<ObjectReferenceImpl> queue) {
1421+ super(mirror, queue);
1422+ this.count = 1;
1423+ this.key = key;
1424+ }
1425+
1426+ int count() {
1427+ return count;
1428+ }
1429+
1430+ void incrementCount() {
1431+ count++;
1432+ }
1433+
1434+ Long key() {
1435+ return key;
1436+ }
1437+
1438+ ObjectReferenceImpl object() {
1439+ return get();
1440+ }
1441+ }
1442+}