summaryrefslogtreecommitdiff
path: root/vm
diff options
context:
space:
mode:
Diffstat (limited to 'vm')
-rw-r--r--vm/reference/gnu/classpath/jdwp/VMFrame.java4
-rw-r--r--vm/reference/gnu/classpath/jdwp/VMIdManager.java426
-rw-r--r--vm/reference/gnu/classpath/jdwp/VMVirtualMachine.java318
3 files changed, 746 insertions, 2 deletions
diff --git a/vm/reference/gnu/classpath/jdwp/VMFrame.java b/vm/reference/gnu/classpath/jdwp/VMFrame.java
index aa1f0b22e..4d3b01074 100644
--- a/vm/reference/gnu/classpath/jdwp/VMFrame.java
+++ b/vm/reference/gnu/classpath/jdwp/VMFrame.java
@@ -15,8 +15,8 @@ General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Classpath; see the file COPYING. If not, write to the
-Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-02111-1307 USA.
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
Linking this library statically or dynamically with other modules is
making a combined work based on this library. Thus, the terms and
diff --git a/vm/reference/gnu/classpath/jdwp/VMIdManager.java b/vm/reference/gnu/classpath/jdwp/VMIdManager.java
new file mode 100644
index 000000000..09173fcf0
--- /dev/null
+++ b/vm/reference/gnu/classpath/jdwp/VMIdManager.java
@@ -0,0 +1,426 @@
+/* VMIdManager.java -- A reference/example implementation of a manager for
+ JDWP object/reference type IDs
+
+ Copyright (C) 2005 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp;
+
+import gnu.classpath.jdwp.exception.InvalidClassException;
+import gnu.classpath.jdwp.exception.InvalidObjectException;
+import gnu.classpath.jdwp.id.*;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+
+/**
+ * This class manages objects and referencetypes that are reported
+ * to the debugger. All objects and referencetypes reported to the
+ * debugger should go through this manager.
+ *
+ * A brief summary of what an <code>IdManager</code> must provide:
+ *
+ * <code>
+ * public ObjectId getObjectId (Object theObject);
+ * public ObjectId get (long id);
+ * public ObjectId readObjectId (ByteBuffer bb);
+ * public ReferenceTypeId getReferenceTypeId (Class clazz);
+ * public ReferenceTypeId getReferenceType (long id);
+ * public ReferenceTypeId readReferenceTypeId (ByteBuffer bb);
+ * </code>
+ *
+ * See the javadoc on these methods later in this file for more
+ * information on these functions.
+ *
+ * <b>NOTE:</b> All IDs handled by the ID manager (all object and reference
+ * type IDs) are assumed to be of type <code>long</code>.
+ *
+ * @author Keith Seitz (keiths@redhat.com)
+ */
+public class VMIdManager
+{
+ // This factory generates ids for objects and types that may
+ // be sent to a debugger.
+ private static class IdFactory
+ {
+ // ID of last object / referencetype
+ private static Object _idLock = new Object ();
+ private static Object _ridLock = new Object ();
+ private static long _lastId = 0;
+ private static long _lastRid = 0;
+
+ // A list of all ID types
+ private static HashMap _idList = new HashMap ();
+
+ // Initialize the id list with known types
+ static
+ {
+ // ObjectId and ArrayId are special cases. See newObjectId.
+ _idList.put (ClassLoaderId.typeClass, ClassLoaderId.class);
+ _idList.put (ClassObjectId.typeClass, ClassObjectId.class);
+ //_idList.put (FieldId.typeClass, FieldId.class);
+ //_idList.put (FrameId.typeClass, FrameId.class);
+ //_idList.put (MethodId.typeClass, MethodId.class);
+ _idList.put (StringId.typeClass, StringId.class);
+ _idList.put (ThreadId.typeClass, ThreadId.class);
+ _idList.put (ThreadGroupId.typeClass, ThreadGroupId.class);
+ }
+
+ /**
+ * Returns a new id for the given object
+ *
+ * @param object the object for which an id is desired
+ * @returns a suitable object id
+ */
+ public static ObjectId newObjectId (SoftReference obj)
+ {
+ ObjectId id = null;
+ Object object = obj.get ();
+
+ // Special case: arrays
+ if (object.getClass ().isArray ())
+ id = new ArrayId ();
+ else
+ {
+ // Loop through all classes until we hit baseclass
+ Class myClass;
+ for (myClass = object.getClass (); myClass != null;
+ myClass = myClass.getSuperclass ())
+ {
+ Class clz = (Class) _idList.get (myClass);
+ if (clz != null)
+ {
+ try
+ {
+ id = (ObjectId) clz.newInstance ();
+ synchronized (_idLock)
+ {
+ id.setId (++_lastId);
+ }
+ return id;
+ }
+ catch (InstantiationException ie)
+ {
+ // This really should not happen
+ throw new RuntimeException ("cannot create new ID", ie);
+ }
+ catch (IllegalAccessException iae)
+ {
+ // This really should not happen
+ throw new RuntimeException ("illegal access of ID", iae);
+ }
+ }
+ }
+
+ /* getSuperclass returned null and no matching ID type found.
+ So it must derive from Object. */
+ id = new ObjectId ();
+ }
+
+ synchronized (_idLock)
+ {
+ id.setId (++_lastId);
+ }
+
+ return id;
+ }
+
+ /**
+ * Returns a new reference type id for the given class
+ *
+ * @param clazz the <code>Class</code> for which an id is desired
+ * @returns a suitable reference type id or null when the
+ * reference is cleared.
+ */
+ public static ReferenceTypeId newReferenceTypeId (SoftReference ref)
+ {
+ ReferenceTypeId id;
+ Class clazz = (Class) ref.get ();
+ if (clazz == null)
+ return null;
+
+ if (clazz.isArray ())
+ id = new ArrayReferenceTypeId ();
+ else if (clazz.isInterface ())
+ id = new InterfaceReferenceTypeId ();
+ else
+ id = new ClassReferenceTypeId ();
+ synchronized (_ridLock)
+ {
+ id.setId (++_lastRid);
+ }
+ return id;
+ }
+ }
+
+ /**
+ * This class is a SoftReferenceIdentity type that is used by
+ * the ID manager.
+ */
+ class ReferenceKey extends SoftReference
+ {
+ // Hash code of referent
+ private int _hash;
+
+ /**
+ * Constructs a new <code>ReferenceKey</code> object
+ * with the given referent.
+ *
+ * <p>This constructor should only be used for object lookups
+ * by the backend.
+ *
+ * @param referent the object to reference
+ */
+ public ReferenceKey (Object referent)
+ {
+ super (referent);
+ _hash = referent.hashCode ();
+ }
+
+ /**
+ * Constructs a new <code>ReferenceKey</code> object
+ * with the given referent and reference queue.
+ *
+ * <p>The JDWP back-end stores a <code>ReferenceKey</code>
+ * with its corresponding <code>JdwpId</code>. This constructor
+ * is used by the back-end when adding new IDs to be managed.
+ *
+ * @param referent the object to reference
+ * @param queue the queue to which to report garbage collections
+ */
+ public ReferenceKey (Object referent, ReferenceQueue queue)
+ {
+ super (referent, queue);
+ _hash = referent.hashCode ();
+ }
+
+ /**
+ * Returns the hash code of the referent.
+ * This seems hacky, but is required in order to use this class
+ * as a hash table key.
+ *
+ * @returns the hash code of the referent
+ */
+ public int hashCode ()
+ {
+ return _hash;
+ }
+
+ /**
+ * Comparator for keys
+ *
+ * This method can be used in two ways:
+ *
+ * <ol>
+ * <li>For table lookups, where we want to compare referents</li>
+ * <li>For clearing GCd objects, where we want to compare the actual
+ * key object (not the referent)</li>
+ * </ol>
+ */
+ public boolean equals (Object obj)
+ {
+ if (obj instanceof ReferenceKey)
+ {
+ ReferenceKey ref = (ReferenceKey) obj;
+
+ /* First check if the two references are the same.
+ If they are, that means we must be clearing GCd objects. */
+ if (this == obj)
+ return true;
+
+ return (ref.get () == get ());
+ }
+
+ return false;
+ }
+ }
+
+ // instance of VMIdManager
+ private static VMIdManager _idm = new VMIdManager ();
+
+ // A reference queue for our objects
+ private ReferenceQueue _refQueue;
+
+ // Mapping of objects (ReferenceKey) to IDs (ObjectId)
+ private Hashtable _oidTable;
+
+ // Mapping of ID numbers (Long) to IDs (ObjectId)
+ private Hashtable _idTable;
+
+ /* Mapping of class (ReferenceKey) to IDs (ReferenceTypeId) for reference
+ types. Unlike other types, reference id types are NEVER released. */
+ private Hashtable _classTable;
+
+ // Mapping of ID numbers (Long) to reference type IDs (ReferenceTypeId)
+ private Hashtable _ridTable;
+
+ /**
+ * Gets the instance of VMIdManager, constructing a new one
+ * if none currently exists.
+ */
+ public static VMIdManager getDefault ()
+ {
+ return _idm;
+ }
+
+ // Constructs a new <code>IdManager</code>
+ private VMIdManager ()
+ {
+ _refQueue = new ReferenceQueue ();
+ _oidTable = new Hashtable (50);
+ _idTable = new Hashtable (50);
+ _classTable = new Hashtable (20);
+ _ridTable = new Hashtable (20);
+ }
+
+ // Updates the object ID table, removing IDs whose objects have
+ // been garbage collected.
+ private void _update ()
+ {
+ Reference ref;
+ while ((ref = _refQueue.poll ()) != null)
+ {
+ ObjectId id = (ObjectId) _oidTable.get (ref);
+ _oidTable.remove (ref);
+ _idTable.remove (new Long (id.getId ()));
+ }
+ }
+
+ /**
+ * Returns an id for the given object, adding it
+ * if it does not have an id.
+ *
+ * @param theObject the object to get an ID/add
+ * @returns the ID of the object
+ */
+ public ObjectId getObjectId (Object theObject)
+ {
+ ReferenceKey ref = new ReferenceKey (theObject, _refQueue);
+ ObjectId id = (ObjectId) _oidTable.get (ref);
+ if (id == null)
+ {
+ // update the tables -- this is an arbitrary place to put this
+ _update ();
+
+ // Object not found. Make new id for it
+ id = IdFactory.newObjectId (ref);
+ _oidTable.put (ref, id);
+ _idTable.put (new Long (id.getId ()), id);
+ }
+
+ return id;
+ }
+
+ /**
+ * Returns the <code>JdwpId</code> for a given ID. Unlike
+ * <code>getId</code>, it throws an exception if the ID is not
+ * known.
+ *
+ * @param id the numerical ID of the desired <code>JdwpId</code>
+ * @throws InvalidObjectException if the ID is not found
+ */
+ public ObjectId get (long id)
+ throws InvalidObjectException
+ {
+ ObjectId oid = (ObjectId) _idTable.get (new Long (id));
+ if (oid == null)
+ throw new InvalidObjectException (id);
+
+ return oid;
+ }
+
+ public ObjectId readObjectId (ByteBuffer bb)
+ throws InvalidObjectException
+ {
+ long id = bb.getLong ();
+ return get (id);
+ }
+
+ /**
+ * Gets the reference type id for the given class, creating
+ * a new one if it does not already have an id
+ *
+ * @param clazz the class for which to get an ID
+ * @returns the ID of the class
+ */
+ public ReferenceTypeId getReferenceTypeId (Class clazz)
+ {
+ ReferenceKey ref = new ReferenceKey (clazz);
+ ReferenceTypeId id = (ReferenceTypeId)_classTable.get (ref);
+ if (id == null)
+ {
+ // Object not found. Make new id for it
+ id = IdFactory.newReferenceTypeId (ref);
+ _classTable.put (ref, id);
+ _ridTable.put (new Long (id.getId ()), id);
+ }
+
+ return id;
+ }
+
+ /**
+ * Returns the <code>ReferenceTypeId</code> for a given ID. Unlike
+ * <code>getReferenceTypeId</code>, it throws an exception if the ID is not
+ * known.
+ *
+ * @param id the numerical ID of the desired reference type
+ * @throws InvalidClassException if the ID is not found
+ */
+ public ReferenceTypeId getReferenceType (long id)
+ throws InvalidClassException
+ {
+ ReferenceTypeId rid = (ReferenceTypeId) _ridTable.get (new Long (id));
+ if (rid == null)
+ throw new InvalidClassException (id);
+
+ return rid;
+ }
+
+ public ReferenceTypeId readReferenceTypeId (ByteBuffer bb)
+ throws InvalidClassException
+ {
+ long id = bb.getLong ();
+ return getReferenceType (id);
+ }
+}
diff --git a/vm/reference/gnu/classpath/jdwp/VMVirtualMachine.java b/vm/reference/gnu/classpath/jdwp/VMVirtualMachine.java
new file mode 100644
index 000000000..30826b7b1
--- /dev/null
+++ b/vm/reference/gnu/classpath/jdwp/VMVirtualMachine.java
@@ -0,0 +1,318 @@
+/* VMVirtualMachine.java -- A reference implementation of a JDWP virtual
+ machine
+
+ Copyright (C) 2005 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.classpath.jdwp;
+
+import gnu.classpath.jdwp.event.EventRequest;
+import gnu.classpath.jdwp.exception.InvalidClassException;
+import gnu.classpath.jdwp.exception.InvalidObjectException;
+import gnu.classpath.jdwp.id.ObjectId;
+import gnu.classpath.jdwp.id.ReferenceTypeId;
+import gnu.classpath.jdwp.util.LineTable;
+import gnu.classpath.jdwp.util.MethodResult;
+import gnu.classpath.jdwp.util.VariableTable;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * A virtual machine according to JDWP.
+ *
+ * @author Keith Seitz <keiths@redhat.com>
+ */
+public class VMVirtualMachine
+{
+ /**
+ * Suspend a thread
+ *
+ * @param thread the thread to suspend
+ */
+ public static native void suspendThread (Thread thread);
+
+ /**
+ * Suspend all threads
+ */
+ public static void suspendAllThreads ()
+ {
+ // Our JDWP thread group -- don't suspend any of those threads
+ Thread current = Thread.currentThread ();
+ ThreadGroup jdwpGroup = current.getThreadGroup ();
+
+ // Find the root ThreadGroup
+ ThreadGroup group = jdwpGroup;
+ ThreadGroup parent = group.getParent ();
+ while (parent != null)
+ {
+ group = parent;
+ parent = group.getParent ();
+ }
+
+ // Get all the threads in the system
+ int num = group.activeCount ();
+ Thread[] threads = new Thread[num];
+ group.enumerate (threads);
+
+ for (int i = 0; i < num; ++i)
+ {
+ Thread t = threads[i];
+ if (t != null)
+ {
+ if (t.getThreadGroup () == jdwpGroup || t == current)
+ {
+ // Don't suspend the current thread or any JDWP thread
+ continue;
+ }
+ else
+ suspendThread (t);
+ }
+ }
+
+ // Now suspend the current thread
+ suspendThread (current);
+ }
+
+ /**
+ * Resume a thread. A thread must be resumed as many times
+ * as it has been suspended.
+ *
+ * @param thread the thread to resume
+ */
+ public static native void resumeThread (Thread thread);
+
+ /**
+ * Resume all threads. This simply decrements the thread's
+ * suspend count. It can not be used to force the application
+ * to run.
+ */
+ public static void resumeAllThreads ()
+ {
+ // Our JDWP thread group -- don't resume
+ Thread current = Thread.currentThread ();
+ ThreadGroup jdwpGroup = current.getThreadGroup ();
+
+ // Find the root ThreadGroup
+ ThreadGroup group = jdwpGroup;
+ ThreadGroup parent = group.getParent ();
+ while (parent != null)
+ {
+ group = parent;
+ parent = group.getParent ();
+ }
+
+ // Get all the threads in the system
+ int num = group.activeCount ();
+ Thread[] threads = new Thread[num];
+ group.enumerate (threads);
+
+ for (int i = 0; i < num; ++i)
+ {
+ Thread t = threads[i];
+ if (t != null)
+ {
+ if (t.getThreadGroup () == jdwpGroup || t == current)
+ {
+ // Don't resume the current thread or any JDWP thread
+ continue;
+ }
+ else
+ resumeThread (t);
+ }
+ }
+ }
+
+ /**
+ * Get the suspend count for a give thread
+ *
+ * @param thread the thread whose suspend count is desired
+ * @return the number of times the thread has been suspended
+ */
+ public static native int getSuspendCount (Thread thread);
+
+ /**
+ * Returns a count of the number of loaded classes in the VM
+ */
+ public static native int getAllLoadedClassesCount ();
+
+ /**
+ * Returns an iterator over all the loaded classes in the VM
+ */
+ public static native Iterator getAllLoadedClasses ();
+
+ /**
+ * Returns the status of the given class
+ *
+ * @param clazz the class whose status is desired
+ * @return a flag containing the class's status
+ * @see JdwpConstants.ClassStatus
+ */
+ public static native int getClassStatus (Class clazz);
+
+
+ /**
+ * Returns the thread's call stack
+ *
+ * @param thread thread for which to get call stack
+ * @param start index of first frame to return
+ * @param length number of frames to return (-1 for all frames)
+ * @return a list of frames
+ */
+ public static native ArrayList getFrames (Thread thread, int strart,
+ int length);
+
+ /**
+ * Returns the frame for a given thread with the frame ID in
+ * the buffer
+ *
+ * I don't like this.
+ *
+ * @param thread the frame's thread
+ * @param bb buffer containing the frame's ID
+ * @return the desired frame
+ */
+ public static native VMFrame getFrame (Thread thread, ByteBuffer bb);
+
+ /**
+ * Returns the number of frames in the thread's stack
+ *
+ * @param thread the thread for which to get a frame count
+ * @return the number of frames in the thread's stack
+ */
+ public static native int getFrameCount (Thread thread);
+
+
+ /**
+ * Returns the status of a thread
+ *
+ * @param thread the thread for which to get status
+ * @return integer status of the thread
+ * @see JdwpConstants.ThreadStatus
+ */
+ public static native int getThreadStatus (Thread thread);
+
+ /**
+ * Returns a list of all classes which this class loader has been
+ * requested to load
+ *
+ * @param cl the class loader
+ * @return a list of all visible classes
+ */
+ public static native ArrayList getLoadRequests (ClassLoader cl);
+
+ /**
+ * Executes a method in the virtual machine
+ *
+ * @param obj instance in which to invoke method (null for static)
+ * @param thread the thread in which to invoke the method
+ * @param clazz the class in which the method is defined
+ * @param method the method to invoke
+ * @param values arguments to pass to method
+ * @param nonVirtual "otherwise, normal virtual invoke
+ * (instance methods only) "
+ * @return a result object containing the results of the invocation
+ */
+ public static native MethodResult executeMethod (Object obj, Thread thread,
+ Class clazz, Method method,
+ Object[] values,
+ boolean nonVirtual);
+
+ /**
+ * "Returns variable information for the method. The variable table
+ * includes arguments and locals declared within the method. For instance
+ * methods, the "this" reference is included in the table. Also, synthetic
+ * variables may be present."
+ *
+ * @param clazz the class in which the method is defined
+ * @param method the method for which variable information is desired
+ * @return a result object containing the information
+ */
+ public static native VariableTable getVarTable (Class clazz, Method method);
+
+ /**
+ * "Returns line number information for the method, if present. The line
+ * table maps source line numbers to the initial code index of the line.
+ * The line table is ordered by code index (from lowest to highest). The
+ * line number information is constant unless a new class definition is
+ * installed using RedefineClasses."
+ *
+ * @param clazz the class in which the method is defined
+ * @param method the method whose line table is desired
+ * @return a result object containing the line table
+ */
+ public static native LineTable getLineTable (Class clazz, Method method);
+
+ /**
+ * "Returns the name of source file in which a reference type was declared"
+ *
+ * @param clazz the class for which to return a source file
+ * @return a string containing the source file name; "no path information
+ * for the file is included"
+ */
+ public static native String getSourceFile (Class clazz);
+
+ /**
+ * Register a request from the debugger
+ *
+ * Virtual machines have two options. Either do nothing and allow
+ * the event manager to take care of the request (useful for broadcast-type
+ * events like class prepare/load/unload, thread start/end, etc.)
+ * or do some internal work to set up the event notification (useful for
+ * execution-related events like breakpoints, single-stepping, etc.).
+ */
+ public static native void registerEvent (EventRequest request);
+
+ /**
+ * Unregisters the given request
+ *
+ * @param request the request to unregister
+ */
+ public static native void unregisterEvent (EventRequest request);
+
+
+ /**
+ * Clear all events of the given kind
+ *
+ * @param kind the type of events to clear
+ */
+ public static native void clearEvents (byte kind);
+}