|
Java example source code file (VirtualMachineImpl.java)
This example Java source code file (VirtualMachineImpl.java) is included in the alvinalexander.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Learn more about this Java project at its project page.
The VirtualMachineImpl.java Java example source code
/*
* Copyright (c) 1998, 2011, 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();
private final ReferenceQueue<ObjectReferenceImpl> referenceQueue = new ReferenceQueue();
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();
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) {
return false;
}
validateVM();
return hasNewCapabilities() &&
capabilitiesNew().canGetInstanceInfo;
}
public boolean canUseSourceNameFilters() {
if (versionInfo().jdwpMajor < 1 ||
versionInfo().jdwpMinor < 6) {
return false;
}
return true;
}
public boolean canForceEarlyReturn() {
validateVM();
return hasNewCapabilities() &&
capabilitiesNew().canForceEarlyReturn;
}
public boolean canBeModified() {
return true;
}
public boolean canGetSourceDebugExtension() {
validateVM();
return hasNewCapabilities() &&
capabilitiesNew().canGetSourceDebugExtension;
}
public boolean canGetClassFileVersion() {
if ( versionInfo().jdwpMajor < 1 &&
versionInfo().jdwpMinor < 6) {
return false;
} else {
return true;
}
}
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 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) {
StringBuffer sb = new StringBuffer("Receiving:");
for (int i = depth; i > 0; --i) {
sb.append(" ");
}
sb.append(string);
printTrace(sb.toString());
}
private synchronized ReferenceTypeImpl addReferenceType(long id,
int tag,
String signature) {
if (typesByID == null) {
initReferenceTypes();
}
ReferenceTypeImpl type = null;
switch(tag) {
case JDWP.TypeTag.CLASS:
type = new ClassTypeImpl(vm, id);
break;
case JDWP.TypeTag.INTERFACE:
type = new InterfaceTypeImpl(vm, id);
break;
case JDWP.TypeTag.ARRAY:
type = new ArrayTypeImpl(vm, id);
break;
default:
throw new InternalException("Invalid reference type tag");
}
/*
* If a signature was specified, make sure to set it ASAP, to
* prevent any needless JDWP command to retrieve it. (for example,
* typesBySignature.add needs the signature, to maintain proper
* ordering.
*/
if (signature != null) {
type.setSignature(signature);
}
typesByID.put(new Long(id), type);
typesBySignature.add(type);
if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
vm.printTrace("Caching new ReferenceType, sig=" + signature +
", id=" + id);
}
return type;
}
synchronized void removeReferenceType(String signature) {
if (typesByID == null) {
return;
}
/*
* There can be multiple classes with the same name. Since
* we can't differentiate here, we first remove all
* matching classes from our cache...
*/
Iterator<ReferenceType> iter = typesBySignature.iterator();
int matches = 0;
while (iter.hasNext()) {
ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
int comp = signature.compareTo(type.signature());
if (comp == 0) {
matches++;
iter.remove();
typesByID.remove(new Long(type.ref()));
if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
vm.printTrace("Uncaching ReferenceType, sig=" + signature +
", id=" + type.ref());
}
/* fix for 4359077 , don't break out. list is no longer sorted
in the order we think
*/
}
}
/*
* ...and if there was more than one, re-retrieve the classes
* with that name
*/
if (matches > 1) {
retrieveClassesBySignature(signature);
}
}
private synchronized List<ReferenceType> findReferenceTypes(String signature) {
if (typesByID == null) {
return new ArrayList<ReferenceType>(0);
}
Iterator<ReferenceType> iter = typesBySignature.iterator();
List<ReferenceType> list = new ArrayList();
while (iter.hasNext()) {
ReferenceTypeImpl type = (ReferenceTypeImpl)iter.next();
int comp = signature.compareTo(type.signature());
if (comp == 0) {
list.add(type);
/* fix for 4359077 , don't break out. list is no longer sorted
in the order we think
*/
}
}
return list;
}
private void initReferenceTypes() {
typesByID = new HashMap<Long, ReferenceType>(300);
typesBySignature = new TreeSet<ReferenceType>();
}
ReferenceTypeImpl referenceType(long ref, byte tag) {
return referenceType(ref, tag, null);
}
ClassTypeImpl classType(long ref) {
return (ClassTypeImpl)referenceType(ref, JDWP.TypeTag.CLASS, null);
}
InterfaceTypeImpl interfaceType(long ref) {
return (InterfaceTypeImpl)referenceType(ref, JDWP.TypeTag.INTERFACE, null);
}
ArrayTypeImpl arrayType(long ref) {
return (ArrayTypeImpl)referenceType(ref, JDWP.TypeTag.ARRAY, null);
}
ReferenceTypeImpl referenceType(long id, int tag,
String signature) {
if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
StringBuffer sb = new StringBuffer();
sb.append("Looking up ");
if (tag == JDWP.TypeTag.CLASS) {
sb.append("Class");
} else if (tag == JDWP.TypeTag.INTERFACE) {
sb.append("Interface");
} else if (tag == JDWP.TypeTag.ARRAY) {
sb.append("ArrayType");
} else {
sb.append("UNKNOWN TAG: " + tag);
}
if (signature != null) {
sb.append(", signature='" + signature + "'");
}
sb.append(", id=" + id);
vm.printTrace(sb.toString());
}
if (id == 0) {
return null;
} else {
ReferenceTypeImpl retType = null;
synchronized (this) {
if (typesByID != null) {
retType = (ReferenceTypeImpl)typesByID.get(new Long(id));
}
if (retType == null) {
retType = addReferenceType(id, tag, signature);
}
}
return retType;
}
}
private JDWP.VirtualMachine.Capabilities capabilities() {
if (capabilities == null) {
try {
capabilities = JDWP.VirtualMachine
.Capabilities.process(vm);
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
return capabilities;
}
private JDWP.VirtualMachine.CapabilitiesNew capabilitiesNew() {
if (capabilitiesNew == null) {
try {
capabilitiesNew = JDWP.VirtualMachine
.CapabilitiesNew.process(vm);
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
return capabilitiesNew;
}
private List<ReferenceType> retrieveClassesBySignature(String signature) {
if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
vm.printTrace("Retrieving matching ReferenceTypes, sig=" + signature);
}
JDWP.VirtualMachine.ClassesBySignature.ClassInfo[] cinfos;
try {
cinfos = JDWP.VirtualMachine.ClassesBySignature.
process(vm, signature).classes;
} catch (JDWPException exc) {
throw exc.toJDIException();
}
int count = cinfos.length;
List<ReferenceType> list = new ArrayList(count);
// Hold lock during processing to improve performance
synchronized (this) {
for (int i = 0; i < count; i++) {
JDWP.VirtualMachine.ClassesBySignature.ClassInfo ci =
cinfos[i];
ReferenceTypeImpl type = referenceType(ci.typeID,
ci.refTypeTag,
signature);
type.setStatus(ci.status);
list.add(type);
}
}
return list;
}
private void retrieveAllClasses1_4() {
JDWP.VirtualMachine.AllClasses.ClassInfo[] cinfos;
try {
cinfos = JDWP.VirtualMachine.AllClasses.process(vm).classes;
} catch (JDWPException exc) {
throw exc.toJDIException();
}
// Hold lock during processing to improve performance
// and to have safe check/set of retrievedAllTypes
synchronized (this) {
if (!retrievedAllTypes) {
// Number of classes
int count = cinfos.length;
for (int i=0; i<count; i++) {
JDWP.VirtualMachine.AllClasses.ClassInfo ci =
cinfos[i];
ReferenceTypeImpl type = referenceType(ci.typeID,
ci.refTypeTag,
ci.signature);
type.setStatus(ci.status);
}
retrievedAllTypes = true;
}
}
}
private void retrieveAllClasses() {
if ((vm.traceFlags & VirtualMachine.TRACE_REFTYPES) != 0) {
vm.printTrace("Retrieving all ReferenceTypes");
}
if (!vm.canGet1_5LanguageFeatures()) {
retrieveAllClasses1_4();
return;
}
/*
* To save time (assuming the caller will be
* using then) we will get the generic sigs too.
*/
JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo[] cinfos;
try {
cinfos = JDWP.VirtualMachine.AllClassesWithGeneric.process(vm).classes;
} catch (JDWPException exc) {
throw exc.toJDIException();
}
// Hold lock during processing to improve performance
// and to have safe check/set of retrievedAllTypes
synchronized (this) {
if (!retrievedAllTypes) {
// Number of classes
int count = cinfos.length;
for (int i=0; i<count; i++) {
JDWP.VirtualMachine.AllClassesWithGeneric.ClassInfo ci =
cinfos[i];
ReferenceTypeImpl type = referenceType(ci.typeID,
ci.refTypeTag,
ci.signature);
type.setGenericSignature(ci.genericSignature);
type.setStatus(ci.status);
}
retrievedAllTypes = true;
}
}
}
void sendToTarget(Packet packet) {
target.send(packet);
}
void waitForTargetReply(Packet packet) {
target.waitForReply(packet);
/*
* If any object disposes have been batched up, send them now.
*/
processBatchedDisposes();
}
Type findBootType(String signature) throws ClassNotLoadedException {
List<ReferenceType> types = allClasses();
Iterator<ReferenceType> iter = types.iterator();
while (iter.hasNext()) {
ReferenceType type = iter.next();
if ((type.classLoader() == null) &&
(type.signature().equals(signature))) {
return type;
}
}
JNITypeParser parser = new JNITypeParser(signature);
throw new ClassNotLoadedException(parser.typeName(),
"Type " + parser.typeName() + " not loaded");
}
BooleanType theBooleanType() {
if (theBooleanType == null) {
synchronized(this) {
if (theBooleanType == null) {
theBooleanType = new BooleanTypeImpl(this);
}
}
}
return theBooleanType;
}
ByteType theByteType() {
if (theByteType == null) {
synchronized(this) {
if (theByteType == null) {
theByteType = new ByteTypeImpl(this);
}
}
}
return theByteType;
}
CharType theCharType() {
if (theCharType == null) {
synchronized(this) {
if (theCharType == null) {
theCharType = new CharTypeImpl(this);
}
}
}
return theCharType;
}
ShortType theShortType() {
if (theShortType == null) {
synchronized(this) {
if (theShortType == null) {
theShortType = new ShortTypeImpl(this);
}
}
}
return theShortType;
}
IntegerType theIntegerType() {
if (theIntegerType == null) {
synchronized(this) {
if (theIntegerType == null) {
theIntegerType = new IntegerTypeImpl(this);
}
}
}
return theIntegerType;
}
LongType theLongType() {
if (theLongType == null) {
synchronized(this) {
if (theLongType == null) {
theLongType = new LongTypeImpl(this);
}
}
}
return theLongType;
}
FloatType theFloatType() {
if (theFloatType == null) {
synchronized(this) {
if (theFloatType == null) {
theFloatType = new FloatTypeImpl(this);
}
}
}
return theFloatType;
}
DoubleType theDoubleType() {
if (theDoubleType == null) {
synchronized(this) {
if (theDoubleType == null) {
theDoubleType = new DoubleTypeImpl(this);
}
}
}
return theDoubleType;
}
VoidType theVoidType() {
if (theVoidType == null) {
synchronized(this) {
if (theVoidType == null) {
theVoidType = new VoidTypeImpl(this);
}
}
}
return theVoidType;
}
PrimitiveType primitiveTypeMirror(byte tag) {
switch (tag) {
case JDWP.Tag.BOOLEAN:
return theBooleanType();
case JDWP.Tag.BYTE:
return theByteType();
case JDWP.Tag.CHAR:
return theCharType();
case JDWP.Tag.SHORT:
return theShortType();
case JDWP.Tag.INT:
return theIntegerType();
case JDWP.Tag.LONG:
return theLongType();
case JDWP.Tag.FLOAT:
return theFloatType();
case JDWP.Tag.DOUBLE:
return theDoubleType();
default:
throw new IllegalArgumentException("Unrecognized primitive tag " + tag);
}
}
private void processBatchedDisposes() {
if (shutdown) {
return;
}
JDWP.VirtualMachine.DisposeObjects.Request[] requests = null;
synchronized(batchedDisposeRequests) {
int size = batchedDisposeRequests.size();
if (size >= DISPOSE_THRESHOLD) {
if ((traceFlags & TRACE_OBJREFS) != 0) {
printTrace("Dispose threashold reached. Will dispose "
+ size + " object references...");
}
requests = new JDWP.VirtualMachine.DisposeObjects.Request[size];
for (int i = 0; i < requests.length; i++) {
SoftObjectReference ref = batchedDisposeRequests.get(i);
if ((traceFlags & TRACE_OBJREFS) != 0) {
printTrace("Disposing object " + ref.key().longValue() +
" (ref count = " + ref.count() + ")");
}
// This is kludgy. We temporarily re-create an object
// reference so that we can correctly pass its id to the
// JDWP command.
requests[i] =
new JDWP.VirtualMachine.DisposeObjects.Request(
new ObjectReferenceImpl(this, ref.key().longValue()),
ref.count());
}
batchedDisposeRequests.clear();
}
}
if (requests != null) {
try {
JDWP.VirtualMachine.DisposeObjects.process(vm, requests);
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
}
private void batchForDispose(SoftObjectReference ref) {
if ((traceFlags & TRACE_OBJREFS) != 0) {
printTrace("Batching object " + ref.key().longValue() +
" for dispose (ref count = " + ref.count() + ")");
}
batchedDisposeRequests.add(ref);
}
private void processQueue() {
Reference<?> ref;
//if ((traceFlags & TRACE_OBJREFS) != 0) {
// printTrace("Checking for softly reachable objects");
//}
while ((ref = referenceQueue.poll()) != null) {
SoftObjectReference softRef = (SoftObjectReference)ref;
removeObjectMirror(softRef);
batchForDispose(softRef);
}
}
synchronized ObjectReferenceImpl objectMirror(long id, int tag) {
// Handle any queue elements that are not strongly reachable
processQueue();
if (id == 0) {
return null;
}
ObjectReferenceImpl object = null;
Long key = new Long(id);
/*
* Attempt to retrieve an existing object object reference
*/
SoftObjectReference ref = objectsByID.get(key);
if (ref != null) {
object = ref.object();
}
/*
* If the object wasn't in the table, or it's soft reference was
* cleared, create a new instance.
*/
if (object == null) {
switch (tag) {
case JDWP.Tag.OBJECT:
object = new ObjectReferenceImpl(vm, id);
break;
case JDWP.Tag.STRING:
object = new StringReferenceImpl(vm, id);
break;
case JDWP.Tag.ARRAY:
object = new ArrayReferenceImpl(vm, id);
break;
case JDWP.Tag.THREAD:
ThreadReferenceImpl thread =
new ThreadReferenceImpl(vm, id);
thread.addListener(this);
object = thread;
break;
case JDWP.Tag.THREAD_GROUP:
object = new ThreadGroupReferenceImpl(vm, id);
break;
case JDWP.Tag.CLASS_LOADER:
object = new ClassLoaderReferenceImpl(vm, id);
break;
case JDWP.Tag.CLASS_OBJECT:
object = new ClassObjectReferenceImpl(vm, id);
break;
default:
throw new IllegalArgumentException("Invalid object tag: " + tag);
}
ref = new SoftObjectReference(key, object, referenceQueue);
/*
* If there was no previous entry in the table, we add one here
* If the previous entry was cleared, we replace it here.
*/
objectsByID.put(key, ref);
if ((traceFlags & TRACE_OBJREFS) != 0) {
printTrace("Creating new " +
object.getClass().getName() + " (id = " + id + ")");
}
} else {
ref.incrementCount();
}
return object;
}
synchronized void removeObjectMirror(ObjectReferenceImpl object) {
// Handle any queue elements that are not strongly reachable
processQueue();
SoftObjectReference ref = objectsByID.remove(new Long(object.ref()));
if (ref != null) {
batchForDispose(ref);
} else {
/*
* If there's a live ObjectReference about, it better be part
* of the cache.
*/
throw new InternalException("ObjectReference " + object.ref() +
" not found in object cache");
}
}
synchronized void removeObjectMirror(SoftObjectReference ref) {
/*
* This will remove the soft reference if it has not been
* replaced in the cache.
*/
objectsByID.remove(ref.key());
}
ObjectReferenceImpl objectMirror(long id) {
return objectMirror(id, JDWP.Tag.OBJECT);
}
StringReferenceImpl stringMirror(long id) {
return (StringReferenceImpl)objectMirror(id, JDWP.Tag.STRING);
}
ArrayReferenceImpl arrayMirror(long id) {
return (ArrayReferenceImpl)objectMirror(id, JDWP.Tag.ARRAY);
}
ThreadReferenceImpl threadMirror(long id) {
return (ThreadReferenceImpl)objectMirror(id, JDWP.Tag.THREAD);
}
ThreadGroupReferenceImpl threadGroupMirror(long id) {
return (ThreadGroupReferenceImpl)objectMirror(id,
JDWP.Tag.THREAD_GROUP);
}
ClassLoaderReferenceImpl classLoaderMirror(long id) {
return (ClassLoaderReferenceImpl)objectMirror(id,
JDWP.Tag.CLASS_LOADER);
}
ClassObjectReferenceImpl classObjectMirror(long id) {
return (ClassObjectReferenceImpl)objectMirror(id,
JDWP.Tag.CLASS_OBJECT);
}
/*
* Implementation of PathSearchingVirtualMachine
*/
private JDWP.VirtualMachine.ClassPaths getClasspath() {
if (pathInfo == null) {
try {
pathInfo = JDWP.VirtualMachine.ClassPaths.process(vm);
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
return pathInfo;
}
public List<String> classPath() {
return Arrays.asList(getClasspath().classpaths);
}
public List<String> bootClassPath() {
return Arrays.asList(getClasspath().bootclasspaths);
}
public String baseDirectory() {
return getClasspath().baseDir;
}
public void setDefaultStratum(String stratum) {
defaultStratum = stratum;
if (stratum == null) {
stratum = "";
}
try {
JDWP.VirtualMachine.SetDefaultStratum.process(vm,
stratum);
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
public String getDefaultStratum() {
return defaultStratum;
}
ThreadGroup threadGroupForJDI() {
return threadGroupForJDI;
}
static private class SoftObjectReference extends SoftReference<ObjectReferenceImpl> {
int count;
Long key;
SoftObjectReference(Long key, ObjectReferenceImpl mirror,
ReferenceQueue<ObjectReferenceImpl> queue) {
super(mirror, queue);
this.count = 1;
this.key = key;
}
int count() {
return count;
}
void incrementCount() {
count++;
}
Long key() {
return key;
}
ObjectReferenceImpl object() {
return get();
}
}
}
Other Java examples (source code examples)
Here is a short list of links related to this Java VirtualMachineImpl.java source code file:
|