gt: 		for(int i = depth; i > 0; --i)
context: /*
   * Copyright (c) 1998, 2016, 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 consulo.internal.com.sun.tools.jdi;
  
  import java.lang.ref.Reference;
  import java.lang.ref.ReferenceQueue;
  import java.lang.ref.SoftReference;
  import java.text.MessageFormat;
  import java.util.ArrayList;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.List;
  import java.util.Map;
  import java.util.TreeSet;
  
  import consulo.internal.com.sun.jdi.*;
  import consulo.internal.com.sun.jdi.connect.spi.Connection;
  import consulo.internal.com.sun.jdi.event.EventQueue;
  import consulo.internal.com.sun.jdi.request.BreakpointRequest;
  import consulo.internal.com.sun.jdi.request.EventRequest;
  import consulo.internal.com.sun.jdi.request.EventRequestManager;
  
  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;
  	public final int sizeofModuleRef;
  
  	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;
  
  	private Map<Long, ModuleReference> modulesByID;
  
  	// 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;
  		sizeofModuleRef = idSizes.objectIDSize;
  
  		/**
  		 * 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<ModuleReference> allModules()
  	{
  		validateVM();
  		List<ModuleReference> modules = retrieveAllModules();
  		return Collections.unmodifiableList(modules);
  	}
  
  	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);
  	}
  
  	public FloatValue mirrorOf(float value)
  	{
  		validateVM();
  		return new FloatValueImpl(this, value);
  	}
  
  	public DoubleValue mirrorOf(double value)
  	{
  		validateVM();
  		return new DoubleValueImpl(this, value);
  	}
  
  	public StringReference mirrorOf(String value)
  	{
  		validateVM();
  		try
  		{
  			return (StringReference) JDWP.VirtualMachine.CreateString.
  					process(vm, value).stringObject;
  		}
  		catch(JDWPException exc)
  		{
  			throw exc.toJDIException();
  		}
  	}
  
  	public VoidValue mirrorOfVoid()
  	{
  		if(voidVal == null)
  		{
  			voidVal = new VoidValueImpl(this);
  		}
  		return voidVal;
  	}
  
  	public long[] instanceCounts(List<? extends ReferenceType> classes)
  	{
  		if(!canGetInstanceInfo())
  		{
  			throw new UnsupportedOperationException("target does not support getting instances");
  		}
  		long[] retValue;
  		ReferenceTypeImpl[] rtArray = new ReferenceTypeImpl[classes.size()];
  		int ii = 0;
  		for(ReferenceType rti : classes)
  		{
  			validateMirror(rti);
  			rtArray[ii++] = (ReferenceTypeImpl) rti;
  		}
  		try
  		{
  			retValue = JDWP.VirtualMachine.InstanceCounts.
  					process(vm, rtArray).counts;
  		}
  		catch(JDWPException exc)
  		{
  			throw exc.toJDIException();
  		}
  
  		return retValue;
  	}
  
  	public void dispose()
  	{
  		validateVM();
  		shutdown = true;
  		try
  		{
  			JDWP.VirtualMachine.Dispose.process(vm);
  		}
  		catch(JDWPException exc)
  		{
  			throw exc.toJDIException();
  		}
  		target.stopListening();
  	}
  
  	public void exit(int exitCode)
  	{
  		validateVM();
  		shutdown = true;
  		try
  		{
  			JDWP.VirtualMachine.Exit.process(vm, exitCode);
  		}
  		catch(JDWPException exc)
  		{
  			throw exc.toJDIException();
  		}
  		target.stopListening();
  	}
  
  	public Process process()
  	{
  		validateVM();
  		return process;
  	}
  
  	private JDWP.VirtualMachine.Version versionInfo()
  	{
  		try
  		{
  			if(versionInfo == null)
  			{
  				// Need not be synchronized since it is static information
  				versionInfo = JDWP.VirtualMachine.Version.process(vm);
  			}
  			return versionInfo;
  		}
  		catch(JDWPException exc)
  		{
  			throw exc.toJDIException();
  		}
  	}
  
  	public String description()
  	{
  		validateVM();
  
  		return MessageFormat.format(vmManager.getString("version_format"), "" + vmManager.majorInterfaceVersion(), "" + vmManager.minorInterfaceVersion(), versionInfo().description);
  	}
  
  	public String version()
  	{
  		validateVM();
  		return versionInfo().vmVersion;
  	}
  
  	public String name()
  	{
  		validateVM();
  		return versionInfo().vmName;
  	}
  
  	public boolean canWatchFieldModification()
  	{
  		validateVM();
  		return capabilities().canWatchFieldModification;
  	}
  
  	public boolean canWatchFieldAccess()
  	{
  		validateVM();
  		return capabilities().canWatchFieldAccess;
  	}
  
  	public boolean canGetBytecodes()
  	{
  		validateVM();
  		return capabilities().canGetBytecodes;
  	}
  
  	public boolean canGetSyntheticAttribute()
  	{
  		validateVM();
  		return capabilities().canGetSyntheticAttribute;
  	}
  
  	public boolean canGetOwnedMonitorInfo()
  	{
  		validateVM();
  		return capabilities().canGetOwnedMonitorInfo;
  	}
  
  	public boolean canGetCurrentContendedMonitor()
  	{
  		validateVM();
  		return capabilities().canGetCurrentContendedMonitor;
  	}
  
  	public boolean canGetMonitorInfo()
  	{
  		validateVM();
  		return capabilities().canGetMonitorInfo;
  	}
  
  	private boolean hasNewCapabilities()
  	{
  		return versionInfo().jdwpMajor > 1 || versionInfo().jdwpMinor >= 4;
  	}
  
  	boolean canGet1_5LanguageFeatures()
  	{
  		return versionInfo().jdwpMajor > 1 || versionInfo().jdwpMinor >= 5;
  	}
  
  	public boolean canUseInstanceFilters()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canUseInstanceFilters;
  	}
  
  	public boolean canRedefineClasses()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canRedefineClasses;
  	}
  
  	public boolean canAddMethod()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canAddMethod;
  	}
  
  	public boolean canUnrestrictedlyRedefineClasses()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canUnrestrictedlyRedefineClasses;
  	}
  
  	public boolean canPopFrames()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canPopFrames;
  	}
  
  	public boolean canGetMethodReturnValues()
  	{
  		return versionInfo().jdwpMajor > 1 || versionInfo().jdwpMinor >= 6;
  	}
  
  	public boolean canGetInstanceInfo()
  	{
  		if(versionInfo().jdwpMajor > 1 || versionInfo().jdwpMinor >= 6)
  		{
  			validateVM();
  			return hasNewCapabilities() && capabilitiesNew().canGetInstanceInfo;
  		}
  		else
  		{
  			return false;
  		}
  	}
  
  	public boolean canUseSourceNameFilters()
  	{
  		return versionInfo().jdwpMajor > 1 || versionInfo().jdwpMinor >= 6;
  	}
  
  	public boolean canForceEarlyReturn()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canForceEarlyReturn;
  	}
  
  	public boolean canBeModified()
  	{
  		return true;
  	}
  
  	public boolean canGetSourceDebugExtension()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canGetSourceDebugExtension;
  	}
  
  	public boolean canGetClassFileVersion()
  	{
  		return versionInfo().jdwpMajor > 1 || versionInfo().jdwpMinor >= 6;
  	}
  
  	public boolean canGetConstantPool()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canGetConstantPool;
  	}
  
  	public boolean canRequestVMDeathEvent()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canRequestVMDeathEvent;
  	}
  
  	public boolean canRequestMonitorEvents()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canRequestMonitorEvents;
  	}
  
  	public boolean canGetMonitorFrameInfo()
  	{
  		validateVM();
  		return hasNewCapabilities() && capabilitiesNew().canGetMonitorFrameInfo;
  	}
  
  	public boolean canGetModuleInfo()
  	{
  		validateVM();
  		return versionInfo().jdwpMajor >= 9;
  	}
  
  	public void setDebugTraceMode(int traceFlags)
  	{
  		validateVM();
  		this.traceFlags = traceFlags;
  		this.traceReceives = (traceFlags & TRACE_RECEIVES) != 0;
  	}
  
  	void printTrace(String string)
  	{
  		System.err.println("[JDI: " + string + "]");
  	}
  
  	void printReceiveTrace(int depth, String string)
  	{
  		StringBuilder sb = new StringBuilder("Receiving:");
  