/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.
*/
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;
// Allow direct access to this field so that that tracing code slows down
// JDI as little as possible when not enabled.
// 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 boolean retrievedAllTypes = false;
// For other languages support
// 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>();
// These are cached once for the life of the VM
// Per-vm singletons for primitive types and for void.
// singleton-ness protected by "synchronized(this)".
// Launched debuggee process
// coordinates state changes and corresponding listener notifications
private boolean initComplete = false;
private boolean shutdown = false;
private void notifyInitCompletion() {
synchronized(initMonitor) {
initComplete = true;
}
}
void waitInitCompletion() {
synchronized(initMonitor) {
while (!initComplete) {
try {
initMonitor.wait();
} catch (InterruptedException e) {
// ignore
}
}
}
}
return state;
}
/*
* ThreadListener implementation
*/
/*
* If any thread is resumed, the VM is considered not suspended.
* Just one thread is being resumed so pass it to thaw.
*/
return true;
}
int sequenceNumber) {
super(null); // Can't use super(this)
vm = this;
this.sequenceNumber = sequenceNumber;
/* Create ThreadGroup to be used by all threads servicing
* this VM.
*/
"JDI [" +
this.hashCode() + "]");
/*
* Set up a thread to communicate with the target VM over
* the specified transport.
*/
/*
* Set up a thread to handle events processed internally
* the JDI implementation.
*/
new InternalEventHandler(this, internalEventQueue);
/*
* Initialize client access to event setting and handling
*/
eventRequestManager = new EventRequestManagerImpl(this);
/*
* Many ids are variably sized, depending on target VM.
* Find out the sizes right away.
*/
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
/**
* 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);
/*
* Tell other threads, notably TargetVM, that initialization
* is complete.
*/
}
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();
* }
*/
}
return this == obj;
}
public int hashCode() {
return System.identityHashCode(this);
}
validateVM();
if (retrievedAllTypes) {
} else {
}
}
validateVM();
if (!retrievedAllTypes) {
}
synchronized (this) {
}
return Collections.unmodifiableList(a);
}
public void
{
validateVM();
if (!canRedefineClasses()) {
throw new UnsupportedOperationException();
}
}
// flush caches and disable caching until the next suspend
try {
} catch (JDWPException exc) {
throw new ClassFormatError(
"class not in class file format");
throw new ClassCircularityError(
"circularity has been detected while initializing a class");
throw new VerifyError(
"verifier detected internal inconsistency or security problem");
throw new UnsupportedClassVersionError(
"version numbers of class are not supported");
throw new UnsupportedOperationException(
"add method not implemented");
throw new UnsupportedOperationException(
"schema change not implemented");
throw new UnsupportedOperationException(
"hierarchy change not implemented");
throw new UnsupportedOperationException(
"delete method not implemented");
throw new UnsupportedOperationException(
"changes to class modifiers not implemented");
throw new UnsupportedOperationException(
"changes to method modifiers not implemented");
throw new NoClassDefFoundError(
"class names do not match");
default:
throw exc.toJDIException();
}
}
// Delete any record of the breakpoints
}
}
// Invalidate any information cached for the classes just redefined.
}
}
validateVM();
return state.allThreads();
}
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.
*/
}
/*
* The VM has been suspended. Additional caching can be done
* as long as there are no pending resumes.
*/
void notifySuspend() {
}
public void suspend() {
validateVM();
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
public void resume() {
validateVM();
new CommandSender() {
public PacketStream send() {
}
};
try {
} 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) {
return;
default:
throw exc.toJDIException();
}
}
}
/*
* No VM validation here. We allow access to the event queue
* after disconnection, so that there is access to the terminating
* events.
*/
return eventQueue;
}
validateVM();
return eventRequestManager;
}
return eventRequestManager;
}
validateVM();
return new BooleanValueImpl(this,value);
}
validateVM();
return new ByteValueImpl(this,value);
}
validateVM();
return new CharValueImpl(this,value);
}
validateVM();
return new ShortValueImpl(this,value);
}
validateVM();
return new IntegerValueImpl(this,value);
}
validateVM();
return new LongValueImpl(this,value);
}
validateVM();
return new FloatValueImpl(this,value);
}
validateVM();
return new DoubleValueImpl(this,value);
}
validateVM();
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
voidVal = new VoidValueImpl(this);
}
return voidVal;
}
if (!canGetInstanceInfo()) {
throw new UnsupportedOperationException(
"target does not support getting instances");
}
long[] retValue ;
int ii = 0;
}
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
return retValue;
}
public void dispose() {
validateVM();
shutdown = true;
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
validateVM();
shutdown = true;
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
validateVM();
return process;
}
try {
if (versionInfo == null) {
// Need not be synchronized since it is static information
}
return versionInfo;
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
validateVM();
}
validateVM();
return versionInfo().vmVersion;
}
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() {
}
boolean canGet1_5LanguageFeatures() {
}
public boolean canUseInstanceFilters() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canRedefineClasses() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canAddMethod() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canUnrestrictedlyRedefineClasses() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canPopFrames() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canGetMethodReturnValues() {
}
public boolean canGetInstanceInfo() {
return false;
}
validateVM();
return hasNewCapabilities() &&
}
public boolean canUseSourceNameFilters() {
return false;
}
return true;
}
public boolean canForceEarlyReturn() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canBeModified() {
return true;
}
public boolean canGetSourceDebugExtension() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canGetClassFileVersion() {
return false;
} else {
return true;
}
}
public boolean canGetConstantPool() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canRequestVMDeathEvent() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canRequestMonitorEvents() {
validateVM();
return hasNewCapabilities() &&
}
public boolean canGetMonitorFrameInfo() {
validateVM();
return hasNewCapabilities() &&
}
validateVM();
this.traceFlags = traceFlags;
}
}
for (int i = depth; i > 0; --i) {
}
}
int tag,
}
switch(tag) {
break;
break;
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.
*/
}
", id=" + id);
}
return type;
}
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...
*/
int matches = 0;
if (comp == 0) {
matches++;
}
/* 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) {
}
}
}
if (comp == 0) {
/* fix for 4359077 , don't break out. list is no longer sorted
in the order we think
*/
}
}
return list;
}
private void initReferenceTypes() {
}
}
}
}
}
} else {
}
}
}
if (id == 0) {
return null;
} else {
synchronized (this) {
}
}
}
return retType;
}
}
if (capabilities == null) {
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
return capabilities;
}
if (capabilitiesNew == null) {
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
return capabilitiesNew;
}
}
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
// Hold lock during processing to improve performance
synchronized (this) {
for (int i = 0; i < count; i++) {
cinfos[i];
}
}
return list;
}
private void retrieveAllClasses1_4() {
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
// Hold lock during processing to improve performance
synchronized (this) {
if (!retrievedAllTypes) {
// Number of classes
for (int i=0; i<count; i++) {
cinfos[i];
}
retrievedAllTypes = true;
}
}
}
private void retrieveAllClasses() {
}
if (!vm.canGet1_5LanguageFeatures()) {
return;
}
/*
* To save time (assuming the caller will be
* using then) we will get the generic sigs too.
*/
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
// Hold lock during processing to improve performance
synchronized (this) {
if (!retrievedAllTypes) {
// Number of classes
for (int i=0; i<count; i++) {
cinfos[i];
}
retrievedAllTypes = true;
}
}
}
}
/*
* If any object disposes have been batched up, send them now.
*/
}
return type;
}
}
}
if (theBooleanType == null) {
synchronized(this) {
if (theBooleanType == null) {
theBooleanType = new BooleanTypeImpl(this);
}
}
}
return theBooleanType;
}
if (theByteType == null) {
synchronized(this) {
if (theByteType == null) {
theByteType = new ByteTypeImpl(this);
}
}
}
return theByteType;
}
if (theCharType == null) {
synchronized(this) {
if (theCharType == null) {
theCharType = new CharTypeImpl(this);
}
}
}
return theCharType;
}
if (theShortType == null) {
synchronized(this) {
if (theShortType == null) {
theShortType = new ShortTypeImpl(this);
}
}
}
return theShortType;
}
if (theIntegerType == null) {
synchronized(this) {
if (theIntegerType == null) {
theIntegerType = new IntegerTypeImpl(this);
}
}
}
return theIntegerType;
}
if (theLongType == null) {
synchronized(this) {
if (theLongType == null) {
theLongType = new LongTypeImpl(this);
}
}
}
return theLongType;
}
if (theFloatType == null) {
synchronized(this) {
if (theFloatType == null) {
theFloatType = new FloatTypeImpl(this);
}
}
}
return theFloatType;
}
if (theDoubleType == null) {
synchronized(this) {
if (theDoubleType == null) {
theDoubleType = new DoubleTypeImpl(this);
}
}
}
return theDoubleType;
}
if (theVoidType == null) {
synchronized(this) {
if (theVoidType == null) {
theVoidType = new VoidTypeImpl(this);
}
}
}
return theVoidType;
}
switch (tag) {
return theBooleanType();
return theByteType();
return theCharType();
return theShortType();
return theIntegerType();
return theLongType();
return theFloatType();
return theDoubleType();
default:
}
}
private void processBatchedDisposes() {
if (shutdown) {
return;
}
synchronized(batchedDisposeRequests) {
if (size >= DISPOSE_THRESHOLD) {
printTrace("Dispose threashold reached. Will dispose "
+ size + " object references...");
}
}
// This is kludgy. We temporarily re-create an object
// reference so that we can correctly pass its id to the
// JDWP command.
requests[i] =
}
}
}
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
}
}
}
private void processQueue() {
//if ((traceFlags & TRACE_OBJREFS) != 0) {
// printTrace("Checking for softly reachable objects");
//}
}
}
// Handle any queue elements that are not strongly reachable
processQueue();
if (id == 0) {
return null;
}
/*
* Attempt to retrieve an existing object object reference
*/
}
/*
* If the object wasn't in the table, or it's soft reference was
* cleared, create a new instance.
*/
switch (tag) {
break;
break;
break;
thread.addListener(this);
break;
break;
break;
break;
default:
}
/*
* If there was no previous entry in the table, we add one here
* If the previous entry was cleared, we replace it here.
*/
printTrace("Creating new " +
}
} else {
}
return object;
}
// Handle any queue elements that are not strongly reachable
processQueue();
} else {
/*
* If there's a live ObjectReference about, it better be part
* of the cache.
*/
" not found in object cache");
}
}
/*
* This will remove the soft reference if it has not been
* replaced in the cache.
*/
}
}
}
}
}
}
}
}
/*
* Implementation of PathSearchingVirtualMachine
*/
try {
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
return pathInfo;
}
}
}
return getClasspath().baseDir;
}
stratum = "";
}
try {
stratum);
} catch (JDWPException exc) {
throw exc.toJDIException();
}
}
return defaultStratum;
}
return threadGroupForJDI;
}
int count;
this.count = 1;
}
int count() {
return count;
}
void incrementCount() {
count++;
}
return key;
}
return get();
}
}
}