/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.jdi; import com.sun.jdi.*;import com.sun.jdi.connect.spi.Connection;import com.sun.jdi.request.EventRequestManager;import com.sun.jdi.request.EventRequest;import com.sun.jdi.request.BreakpointRequest;import com.sun.jdi.event.EventQueue; import java.util.*;import java.text.MessageFormat;import java.lang.ref.ReferenceQueue;import java.lang.ref.Reference;import java.lang.ref.SoftReference;import java.lang.ref.WeakReference; class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtualMachine, ThreadListener { // VM Level exported variables, these // are unique to a given vm public final int sizeofFieldRef; public final int sizeofMethodRef; public final int sizeofObjectRef; public final int sizeofClassRef; public final int sizeofFrameRef; final int sequenceNumber; private final TargetVM target; private final EventQueueImpl eventQueue; private final EventRequestManagerImpl internalEventRequestManager; private final EventRequestManagerImpl eventRequestManager; final VirtualMachineManagerImpl vmManager; private final ThreadGroup threadGroupForJDI; // Allow direct access to this field so that that tracing code slows down // JDI as little as possible when not enabled. int traceFlags = TRACE_NONE; static int TRACE_RAW_SENDS = 0x01000000; static int TRACE_RAW_RECEIVES = 0x02000000; boolean traceReceives = false; // pre-compute because of frequency // ReferenceType access - updated with class prepare and unload events // Protected by "synchronized(this)". "retrievedAllTypes" may be // tested unsynchronized (since once true, it stays true), but must // be set synchronously private Map<Long, ReferenceType> typesByID; private TreeSet<ReferenceType> typesBySignature; private boolean retrievedAllTypes = false; // For other languages support private String defaultStratum = null; // ObjectReference cache // "objectsByID" protected by "synchronized(this)". private final Map<Long, SoftObjectReference> objectsByID = new HashMap<Long, SoftObjectReference>(); private final ReferenceQueue<ObjectReferenceImpl> referenceQueue = new ReferenceQueue<ObjectReferenceImpl>(); static private final int DISPOSE_THRESHOLD = 50; private final List<SoftObjectReference> batchedDisposeRequests = Collections.synchronizedList(new ArrayList<SoftObjectReference>(DISPOSE_THRESHOLD + 10)); // These are cached once for the life of the VM private JDWP.VirtualMachine.Version versionInfo; private JDWP.VirtualMachine.ClassPaths pathInfo; private JDWP.VirtualMachine.Capabilities capabilities = null; private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew = null; // Per-vm singletons for primitive types and for void. // singleton-ness protected by "synchronized(this)". private BooleanType theBooleanType; private ByteType theByteType; private CharType theCharType; private ShortType theShortType; private IntegerType theIntegerType; private LongType theLongType; private FloatType theFloatType; private DoubleType theDoubleType; private VoidType theVoidType; private VoidValue voidVal; // Launched debuggee process private Process process; // coordinates state changes and corresponding listener notifications private VMState state = new VMState(this); private Object initMonitor = new Object(); private boolean initComplete = false; private boolean shutdown = false; private void notifyInitCompletion() { synchronized(initMonitor) { initComplete = true; initMonitor.notifyAll(); } } void waitInitCompletion() { synchronized(initMonitor) { while (!initComplete) { try { initMonitor.wait(); } catch (InterruptedException e) { // ignore } } } } VMState state() { return state; } /* * ThreadListener implementation */ public boolean threadResumable(ThreadAction action) { /* * If any thread is resumed, the VM is considered not suspended. * Just one thread is being resumed so pass it to thaw. */ state.thaw(action.thread()); return true; } VirtualMachineImpl(VirtualMachineManager manager, Connection connection, Process process, int sequenceNumber) { super(null); // Can't use super(this) vm = this; this.vmManager = (VirtualMachineManagerImpl)manager; this.process = process; this.sequenceNumber = sequenceNumber; /* Create ThreadGroup to be used by all threads servicing * this VM. */ threadGroupForJDI = new ThreadGroup(vmManager.mainGroupForJDI(), "JDI [" + this.hashCode() + "]"); /* * Set up a thread to communicate with the target VM over * the specified transport. */ target = new TargetVM(this, connection); /* * Set up a thread to handle events processed internally * the JDI implementation. */ EventQueueImpl internalEventQueue = new EventQueueImpl(this, target); new InternalEventHandler(this, internalEventQueue); /* * Initialize client access to event setting and handling */ eventQueue = new EventQueueImpl(this, target); eventRequestManager = new EventRequestManagerImpl(this); target.start(); /* * Many ids are variably sized, depending on target VM. * Find out the sizes right away. */ JDWP.VirtualMachine.IDSizes idSizes; try { idSizes = JDWP.VirtualMachine.IDSizes.process(vm); } catch (JDWPException exc) { throw exc.toJDIException(); } sizeofFieldRef = idSizes.fieldIDSize; sizeofMethodRef = idSizes.methodIDSize; sizeofObjectRef = idSizes.objectIDSize; sizeofClassRef = idSizes.referenceTypeIDSize; sizeofFrameRef = idSizes.frameIDSize; /** * Set up requests needed by internal event handler. * Make sure they are distinguished by creating them with * an internal event request manager. * * Warning: create events only with SUSPEND_NONE policy. * In the current implementation other policies will not * be handled correctly when the event comes in. (notfiySuspend() * will not be properly called, and if the event is combined * with external events in the same set, suspend policy is not * correctly determined for the internal vs. external event sets) */ internalEventRequestManager = new EventRequestManagerImpl(this); EventRequest er = internalEventRequestManager.createClassPrepareRequest(); er.setSuspendPolicy(EventRequest.SUSPEND_NONE); er.enable(); er = internalEventRequestManager.createClassUnloadRequest(); er.setSuspendPolicy(EventRequest.SUSPEND_NONE); er.enable(); /* * Tell other threads, notably TargetVM, that initialization * is complete. */ notifyInitCompletion(); } EventRequestManagerImpl getInternalEventRequestManager() { return internalEventRequestManager; } void validateVM() { /* * We no longer need to do this. The spec now says * that a VMDisconnected _may_ be thrown in these * cases, not that it _will_ be thrown. * So, to simplify things we will just let the * caller's of this method proceed with their business. * If the debuggee is disconnected, either because it * crashed or finished or something, or because the * debugger called exit() or dispose(), then if * we end up trying to communicate with the debuggee, * code in TargetVM will throw a VMDisconnectedException. * This means that if we can satisfy a request without * talking to the debuggee, (eg, with cached data) then * VMDisconnectedException will _not_ be thrown. * if (shutdown) { * throw new VMDisconnectedException(); * } */ } public boolean equals(Object obj) { return this == obj; } public int hashCode() { return System.identityHashCode(this); } public List<ReferenceType> classesByName(String className) { validateVM(); String signature = JNITypeParser.typeNameToSignature(className); List<ReferenceType> list; if (retrievedAllTypes) { list = findReferenceTypes(signature); } else { list = retrieveClassesBySignature(signature); } return Collections.unmodifiableList(list); } public List<ReferenceType> allClasses() { validateVM(); if (!retrievedAllTypes) { retrieveAllClasses(); } ArrayList<ReferenceType> a; synchronized (this) { a = new ArrayList<ReferenceType>(typesBySignature); } return Collections.unmodifiableList(a); } public void redefineClasses(Map<? extends ReferenceType,byte[]> classToBytes) { int cnt = classToBytes.size(); JDWP.VirtualMachine.RedefineClasses.ClassDef[] defs = new JDWP.VirtualMachine.RedefineClasses.ClassDef[cnt]; validateVM(); if (!canRedefineClasses()) { throw new UnsupportedOperationException(); } Iterator it = classToBytes.entrySet().iterator(); for (int i = 0; it.hasNext(); i++) { Map.Entry entry = (Map.Entry)it.next(); ReferenceTypeImpl refType = (ReferenceTypeImpl)entry.getKey(); validateMirror(refType); defs[i] = new JDWP.VirtualMachine.RedefineClasses .ClassDef(refType, (byte[])entry.getValue()); } // flush caches and disable caching until the next suspend vm.state().thaw(); try { JDWP.VirtualMachine.RedefineClasses. process(vm, defs); } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.INVALID_CLASS_FORMAT : throw new ClassFormatError( "class not in class file format"); case JDWP.Error.CIRCULAR_CLASS_DEFINITION : throw new ClassCircularityError( "circularity has been detected while initializing a class"); case JDWP.Error.FAILS_VERIFICATION : throw new VerifyError( "verifier detected internal inconsistency or security problem"); case JDWP.Error.UNSUPPORTED_VERSION : throw new UnsupportedClassVersionError( "version numbers of class are not supported"); case JDWP.Error.ADD_METHOD_NOT_IMPLEMENTED: throw new UnsupportedOperationException( "add method not implemented"); case JDWP.Error.SCHEMA_CHANGE_NOT_IMPLEMENTED : throw new UnsupportedOperationException( "schema change not implemented"); case JDWP.Error.HIERARCHY_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( "hierarchy change not implemented"); case JDWP.Error.DELETE_METHOD_NOT_IMPLEMENTED : throw new UnsupportedOperationException( "delete method not implemented"); case JDWP.Error.CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( "changes to class modifiers not implemented"); case JDWP.Error.METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED : throw new UnsupportedOperationException( "changes to method modifiers not implemented"); case JDWP.Error.NAMES_DONT_MATCH : throw new NoClassDefFoundError( "class names do not match"); default: throw exc.toJDIException(); } } // Delete any record of the breakpoints List<BreakpointRequest> toDelete = new ArrayList<BreakpointRequest>(); EventRequestManager erm = eventRequestManager(); it = erm.breakpointRequests().iterator(); while (it.hasNext()) { BreakpointRequest req = (BreakpointRequest)it.next(); if (classToBytes.containsKey(req.location().declaringType())) { toDelete.add(req); } } erm.deleteEventRequests(toDelete); // Invalidate any information cached for the classes just redefined. it = classToBytes.keySet().iterator(); while (it.hasNext()) { ReferenceTypeImpl rti = (ReferenceTypeImpl)it.next(); rti.noticeRedefineClass(); } } public List<ThreadReference> allThreads() { validateVM(); return state.allThreads(); } public List<ThreadGroupReference> topLevelThreadGroups() { validateVM(); return state.topLevelThreadGroups(); } /* * Sends a command to the back end which is defined to do an * implicit vm-wide resume. The VM can no longer be considered * suspended, so certain cached data must be invalidated. */ PacketStream sendResumingCommand(CommandSender sender) { return state.thawCommand(sender); } /* * The VM has been suspended. Additional caching can be done * as long as there are no pending resumes. */ void notifySuspend() { state.freeze(); } public void suspend() { validateVM(); try { JDWP.VirtualMachine.Suspend.process(vm); } catch (JDWPException exc) { throw exc.toJDIException(); } notifySuspend(); } public void resume() { validateVM(); CommandSender sender = new CommandSender() { public PacketStream send() { return JDWP.VirtualMachine.Resume.enqueueCommand(vm); } }; try { PacketStream stream = state.thawCommand(sender); JDWP.VirtualMachine.Resume.waitForReply(vm, stream); } catch (VMDisconnectedException exc) { /* * If the debugger makes a VMDeathRequest with SUSPEND_ALL, * then when it does an EventSet.resume after getting the * VMDeathEvent, the normal flow of events is that the * BE shuts down, but the waitForReply comes back ok. In this * case, the run loop in TargetVM that is waiting for a packet * gets an EOF because the socket closes. It generates a * VMDisconnectedEvent and everyone is happy. * However, sometimes, the BE gets shutdown before this * waitForReply completes. In this case, TargetVM.waitForReply * gets awakened with no reply and so gens a VMDisconnectedException * which is not what we want. It might be possible to fix this * in the BE, but it is ok to just ignore the VMDisconnectedException * here. This will allow the VMDisconnectedEvent to be generated * correctly. And, if the debugger should happen to make another * request, it will get a VMDisconnectedException at that time. */ } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.VM_DEAD: return; default: throw exc.toJDIException(); } } } public EventQueue eventQueue() { /* * No VM validation here. We allow access to the event queue * after disconnection, so that there is access to the terminating * events. */ return eventQueue; } public EventRequestManager eventRequestManager() { validateVM(); return eventRequestManager; } EventRequestManagerImpl eventRequestManagerImpl() { return eventRequestManager; } public BooleanValue mirrorOf(boolean value) { validateVM(); return new BooleanValueImpl(this,value); } public ByteValue mirrorOf(byte value) { validateVM(); return new ByteValueImpl(this,value); } public CharValue mirrorOf(char value) { validateVM(); return new CharValueImpl(this,value); } public ShortValue mirrorOf(short value) { validateVM(); return new ShortValueImpl(this,value); } public IntegerValue mirrorOf(int value) { validateVM(); return new IntegerValueImpl(this,value); } public LongValue mirrorOf(long value) { validateVM(); return new LongValueImpl(this,value); }Lines 1–500 of 1442. Load more
/* * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.tools.jdi; import com.sun.jdi.*; import com.sun.jdi.connect.spi.Connection; import com.sun.jdi.request.EventRequestManager; import com.sun.jdi.request.EventRequest; import com.sun.jdi.request.BreakpointRequest; import com.sun.jdi.event.EventQueue; import java.util.*; import java.text.MessageFormat; import java.lang.ref.ReferenceQueue; import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; class VirtualMachineImpl extends MirrorImpl implements PathSearchingVirtualMachine, ThreadListener { // VM Level exported variables, these // are unique to a given vm public final int sizeofFieldRef; public final int sizeofMethodRef; public final int sizeofObjectRef; public final int sizeofClassRef; public final int sizeofFrameRef; final int sequenceNumber; private final TargetVM target; private final EventQueueImpl eventQueue; private final EventRequestManagerImpl internalEventRequestManager; private final EventRequestManagerImpl eventRequestManager; final VirtualMachineManagerImpl vmManager; private final ThreadGroup threadGroupForJDI; // Allow direct access to this field so that that tracing code slows down // JDI as little as possible when not enabled. int traceFlags = TRACE_NONE; static int TRACE_RAW_SENDS = 0x01000000; static int TRACE_RAW_RECEIVES = 0x02000000; boolean traceReceives = false; // pre-compute because of frequency // ReferenceType access - updated with class prepare and unload events // Protected by "synchronized(this)". "retrievedAllTypes" may be // tested unsynchronized (since once true, it stays true), but must // be set synchronously private Map<Long, ReferenceType> typesByID; private TreeSet<ReferenceType> typesBySignature; private boolean retrievedAllTypes = false; // For other languages support private String defaultStratum = null; // ObjectReference cache // "objectsByID" protected by "synchronized(this)". private final Map<Long, SoftObjectReference> objectsByID = new HashMap<Long, SoftObjectReference>(); private final ReferenceQueue<ObjectReferenceImpl> referenceQueue = new ReferenceQueue<ObjectReferenceImpl>(); static private final int DISPOSE_THRESHOLD = 50; private final List<SoftObjectReference> batchedDisposeRequests = Collections.synchronizedList(new ArrayList<SoftObjectReference>(DISPOSE_THRESHOLD + 10)); // These are cached once for the life of the VM private JDWP.VirtualMachine.Version versionInfo; private JDWP.VirtualMachine.ClassPaths pathInfo; private JDWP.VirtualMachine.Capabilities capabilities = null; private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew = null; // Per-vm singletons for primitive types and for void. // singleton-ness protected by "synchronized(this)". private BooleanType theBooleanType; private ByteType theByteType; private CharType theCharType; private ShortType theShortType; private IntegerType theIntegerType; private LongType theLongType; private FloatType theFloatType; private DoubleType theDoubleType; private VoidType theVoidType; private VoidValue voidVal; // Launched debuggee process private Process process; // coordinates state changes and corresponding listener notifications private VMState state = new VMState(this); private Object initMonitor = new Object(); private boolean initComplete = false; private boolean shutdown = false; private void notifyInitCompletion() { synchronized(initMonitor) { initComplete = true; initMonitor.notifyAll(); } } void waitInitCompletion() { synchronized(initMonitor) { while (!initComplete) { try { initMonitor.wait(); } catch (InterruptedException e) { // ignore } } } } VMState state() { return state; } /* * ThreadListener implementation */ public boolean threadResumable(ThreadAction action) { /* * If any thread is resumed, the VM is considered not suspended. * Just one thread is being resumed so pass it to thaw. */ state.thaw(action.thread()); return true; } VirtualMachineImpl(VirtualMachineManager manager, Connection connection, Process process, int sequenceNumber) { super(null); // Can't use super(this) vm = this; this.vmManager = (VirtualMachineManagerImpl)manager; this.process = process; this.sequenceNumber = sequenceNumber; /* Create ThreadGroup to be used by all threads servicing * this VM. */ threadGroupForJDI = new ThreadGroup(vmManager.mainGroupForJDI(), "JDI [" + this.hashCode() + "]"); /* * Set up a thread to communicate with the target VM over * the specified transport. */ target = new TargetVM(this, connection); /* * Set up a thread to handle events processed internally * the JDI implementation. */ EventQueueImpl internalEventQueue = new EventQueueImpl(this, target); new InternalEventHandler(this, internalEventQueue); /* * Initialize client access to event setting and handling */ eventQueue = new EventQueueImpl(this, target); eventRequestManager = new EventRequestManagerImpl(this); target.start(); /* * Many ids are variably sized, depending on target VM. * Find out the sizes right away. */ JDWP.VirtualMachine.IDSizes idSizes; try { idSizes = JDWP.VirtualMachine.IDSizes.process(vm); } catch (JDWPException exc) { throw exc.toJDIException(); } sizeofFieldRef = idSizes.fieldIDSize; sizeofMethodRef = idSizes.methodIDSize; sizeofObjectRef = idSizes.objectIDSize; sizeofClassRef = idSizes.referenceTypeIDSize; sizeofFrameRef = idSizes.frameIDSize; /** * Set up requests needed by internal event handler. * Make sure they are distinguished by creating them with * an internal event request manager. * * Warning: create events only with SUSPEND_NONE policy. * In the current implementation other policies will not * be handled correctly when the event comes in. (notfiySuspend() * will not be properly called, and if the event is combined * with external events in the same set, suspend policy is not * correctly determined for the internal vs. external event sets) */ internalEventRequestManager = new EventRequestManagerImpl(this); EventRequest er = internalEventRequestManager.createClassPrepareRequest(); er.setSuspendPolicy(EventRequest.SUSPEND_NONE); er.enable(); er = internalEventRequestManager.createClassUnloadRequest(); er.setSuspendPolicy(EventRequest.SUSPEND_NONE); er.enable(); /* * Tell other threads, notably TargetVM, that initialization * is complete. */ notifyInitCompletion(); } EventRequestManagerImpl getInternalEventRequestManager() { return internalEventRequestManager; } void validateVM() { /* * We no longer need to do this. The spec now says * that a VMDisconnected _may_ be thrown in these * cases, not that it _will_ be thrown. * So, to simplify things we will just let the * caller's of this method proceed with their business. * If the debuggee is disconnected, either because it * crashed or finished or something, or because the * debugger called exit() or dispose(), then if * we end up trying to communicate with the debuggee, * code in TargetVM will throw a VMDisconnectedException. * This means that if we can satisfy a request without * talking to the debuggee, (eg, with cached data) then * VMDisconnectedException will _not_ be thrown. * if (shutdown) { * throw new VMDisconnectedException(); * } */ } public boolean equals(Object obj) { return this == obj; } public int hashCode() { return System.identityHashCode(this); } public List<ReferenceType> classesByName(String className) { validateVM(); String signature = JNITypeParser.typeNameToSignature(className); List<ReferenceType> list; if (retrievedAllTypes) { list = findReferenceTypes(signature); } else { list = retrieveClassesBySignature(signature); } return Collections.unmodifiableList(list); } public List<ReferenceType> allClasses() { validateVM(); if (!retrievedAllTypes) { retrieveAllClasses(); } ArrayList<ReferenceType> a; synchronized (this) { a = new ArrayList<ReferenceType>(typesBySignature); } return Collections.unmodifiableList(a); } public void redefineClasses(Map<? extends ReferenceType,byte[]> classToBytes) { int cnt = classToBytes.size(); JDWP.VirtualMachine.RedefineClasses.ClassDef[] defs = new JDWP.VirtualMachine.RedefineClasses.ClassDef[cnt]; validateVM(); if (!canRedefineClasses()) { throw new UnsupportedOperationException(); } Iterator it = classToBytes.entrySet().iterator(); for (int i = 0; it.hasNext(); i++) { Map.Entry entry = (Map.Entry)it.next(); ReferenceTypeImpl refType = (ReferenceTypeImpl)entry.getKey(); validateMirror(refType); defs[i] = new JDWP.VirtualMachine.RedefineClasses .ClassDef(refType, (byte[])entry.getValue()); } // flush caches and disable caching until the next suspend vm.state().thaw(); try { JDWP.VirtualMachine.RedefineClasses. process(vm, defs); } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.INVALID_CLASS_FORMAT : throw new ClassFormatError( "class not in class file format"); case JDWP.Error.CIRCULAR_CLASS_DEFINITION : throw new ClassCircularityError( "circularity has been detected while initializing a class"); case JDWP.Error.FAILS_VERIFICATION : throw new VerifyError( "verifier detected internal inconsistency or security problem"); case JDWP.Error.UNSUPPORTED_VERSION : throw new UnsupportedClassVersionError( "version numbers of class are not supported"); case JDWP.Error.ADD_METHOD_NOT_IMPLEMENTED: throw new UnsupportedOperationException( "add method not implemented"); case JDWP.Error.SCHEMA_CHANGE_NOT_IMPLEMENTED : throw new UnsupportedOperationException( "schema change not implemented"); case JDWP.Error.HIERARCHY_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( "hierarchy change not implemented"); case JDWP.Error.DELETE_METHOD_NOT_IMPLEMENTED : throw new UnsupportedOperationException( "delete method not implemented"); case JDWP.Error.CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED: throw new UnsupportedOperationException( "changes to class modifiers not implemented"); case JDWP.Error.METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED : throw new UnsupportedOperationException( "changes to method modifiers not implemented"); case JDWP.Error.NAMES_DONT_MATCH : throw new NoClassDefFoundError( "class names do not match"); default: throw exc.toJDIException(); } } // Delete any record of the breakpoints List<BreakpointRequest> toDelete = new ArrayList<BreakpointRequest>(); EventRequestManager erm = eventRequestManager(); it = erm.breakpointRequests().iterator(); while (it.hasNext()) { BreakpointRequest req = (BreakpointRequest)it.next(); if (classToBytes.containsKey(req.location().declaringType())) { toDelete.add(req); } } erm.deleteEventRequests(toDelete); // Invalidate any information cached for the classes just redefined. it = classToBytes.keySet().iterator(); while (it.hasNext()) { ReferenceTypeImpl rti = (ReferenceTypeImpl)it.next(); rti.noticeRedefineClass(); } } public List<ThreadReference> allThreads() { validateVM(); return state.allThreads(); } public List<ThreadGroupReference> topLevelThreadGroups() { validateVM(); return state.topLevelThreadGroups(); } /* * Sends a command to the back end which is defined to do an * implicit vm-wide resume. The VM can no longer be considered * suspended, so certain cached data must be invalidated. */ PacketStream sendResumingCommand(CommandSender sender) { return state.thawCommand(sender); } /* * The VM has been suspended. Additional caching can be done * as long as there are no pending resumes. */ void notifySuspend() { state.freeze(); } public void suspend() { validateVM(); try { JDWP.VirtualMachine.Suspend.process(vm); } catch (JDWPException exc) { throw exc.toJDIException(); } notifySuspend(); } public void resume() { validateVM(); CommandSender sender = new CommandSender() { public PacketStream send() { return JDWP.VirtualMachine.Resume.enqueueCommand(vm); } }; try { PacketStream stream = state.thawCommand(sender); JDWP.VirtualMachine.Resume.waitForReply(vm, stream); } catch (VMDisconnectedException exc) { /* * If the debugger makes a VMDeathRequest with SUSPEND_ALL, * then when it does an EventSet.resume after getting the * VMDeathEvent, the normal flow of events is that the * BE shuts down, but the waitForReply comes back ok. In this * case, the run loop in TargetVM that is waiting for a packet * gets an EOF because the socket closes. It generates a * VMDisconnectedEvent and everyone is happy. * However, sometimes, the BE gets shutdown before this * waitForReply completes. In this case, TargetVM.waitForReply * gets awakened with no reply and so gens a VMDisconnectedException * which is not what we want. It might be possible to fix this * in the BE, but it is ok to just ignore the VMDisconnectedException * here. This will allow the VMDisconnectedEvent to be generated * correctly. And, if the debugger should happen to make another * request, it will get a VMDisconnectedException at that time. */ } catch (JDWPException exc) { switch (exc.errorCode()) { case JDWP.Error.VM_DEAD: return; default: throw exc.toJDIException(); } } } public EventQueue eventQueue() { /* * No VM validation here. We allow access to the event queue * after disconnection, so that there is access to the terminating * events. */ return eventQueue; } public EventRequestManager eventRequestManager() { validateVM(); return eventRequestManager; } EventRequestManagerImpl eventRequestManagerImpl() { return eventRequestManager; } public BooleanValue mirrorOf(boolean value) { validateVM(); return new BooleanValueImpl(this,value); } public ByteValue mirrorOf(byte value) { validateVM(); return new ByteValueImpl(this,value); } public CharValue mirrorOf(char value) { validateVM(); return new CharValueImpl(this,value); } public ShortValue mirrorOf(short value) { validateVM(); return new ShortValueImpl(this,value); } public IntegerValue mirrorOf(int value) { validateVM(); return new IntegerValueImpl(this,value); } public LongValue mirrorOf(long value) { validateVM(); return new LongValueImpl(this,value); }