On Mon, 2005-06-20 at 09:04 -0600, Tom Tromey wrote:
> >>>>> "Keith" == Keith Seitz <[EMAIL PROTECTED]> writes:
> 
> Keith> Unfortunately, with the WeakHashMap, there is no way to get the keys 
> put
> Keith> into a ReferenceQueue (that I can see at least). Consequently, I'll
> Keith> never know when to clean up the idTable unless I iterate over the 
> table,
> Keith> asking each ID whether its object is still valid.
> 
> It seems like you could make a second WeakReference just for the queue.
> A little ugly though.

I'm not sure I follow: Are you saying I could wrap the
ObjectId/ReferenceTypeId with a weak reference (who is associated with
another ReferenceQueue) for collection?

I guess I could do that, yeah. So then I'd have two WeakHashMaps of
Object/Class -> ID tables, where WeakHashMap automagically wraps the
Object/Class in a WeakReference.

For the other tables (Long -> ID), I wrap the ID in a WeakReference
(with a specified queue). So when the Object/Class is garbage collected,
its entry in the WeakHashMap is lost, there is no longer any strong
reference to the ID and it will be garbage collected, too.

Yeah, that seems like it might work. I've attached a new patch which
incorporates these changes.

Comments/questions/concerns?
Keith
Index: gnu/classpath/jdwp/id/IdManager.java
===================================================================
RCS file: gnu/classpath/jdwp/id/IdManager.java
diff -N gnu/classpath/jdwp/id/IdManager.java
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ gnu/classpath/jdwp/id/IdManager.java	21 Jun 2005 18:55:53 -0000
@@ -0,0 +1,232 @@
+/* IdManager.java -- 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., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 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.id;
+
+import gnu.classpath.jdwp.exception.InvalidClassException;
+import gnu.classpath.jdwp.exception.InvalidObjectException;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
+
+/**
+ * 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.
+ *
+ * @author Keith Seitz  ([EMAIL PROTECTED])
+ */
+public class IdManager
+{
+  // Reference queues for invalid ObjectIds and ReferenceTypeIds
+  private ReferenceQueue _oidRefQueue;
+  private ReferenceQueue _ridRefQueue;
+
+  /* Mapping of objects (Object) to IDs (ObjectId). Table is a
+     synchronized WeakHashMap. */
+  private Map _oidTable;
+
+  /* Mapping of ID numbers (Long) to IDs (ObjectId). IDs are
+     stored as WeakReferences */
+  private Hashtable _idTable;
+
+  /* Mapping of class (Class) to IDs (ReferenceTypeId) for reference
+     types. Table is a synchronized WeakHashMap. */
+  private Map _classTable;
+
+  /* Mapping of ID numbers (Long) to reference type IDs (ReferenceTypeId).
+     IDs are stored as WeakReferences */
+  private Hashtable _ridTable;
+
+  /**
+   * Constructs a new <code>IdManager</code>
+   */
+  public IdManager ()
+  {
+    _oidRefQueue = new ReferenceQueue ();
+    _ridRefQueue = new ReferenceQueue ();
+    _oidTable = Collections.synchronizedMap (new WeakHashMap (50));
+    _idTable = new Hashtable (50);
+    _classTable = Collections.synchronizedMap (new WeakHashMap (20));
+    _ridTable = new Hashtable (20);
+  }
+
+  // Updates the ID tables, removing IDs whose objects/classes have
+  // been garbage collected.
+  private void _update ()
+  {
+    Reference ref;
+    while ((ref = _oidRefQueue.poll ()) != null)
+      {
+	ObjectId id = (ObjectId) ref.get ();
+	_oidTable.remove (new Long (id.getId ()));
+      }
+
+    while ((ref = _ridRefQueue.poll ()) != null)
+      {
+	ReferenceTypeId id = (ReferenceTypeId) ref.get ();
+	_ridTable.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 getId (Object theObject)
+  {
+    ObjectId id = (ObjectId) _oidTable.get (theObject);
+    if (id == null)
+      {
+	// update the tables -- this is an arbitrary place to put this
+	_update ();
+
+	// Object not found. Make new id for it
+	id = JdwpIdFactory.newId (theObject);
+	_oidTable.put (theObject, id);
+	_idTable.put (new Long (id.getId ()),
+		      new WeakReference (id, _oidRefQueue));
+      }
+
+    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
+  {
+    WeakReference ref = (WeakReference) _idTable.get (new Long (id));
+    ObjectId oid = (ObjectId) ref.get ();
+    if (oid == null)
+      throw new InvalidObjectException (id);
+ 
+    return oid;
+  }
+
+  /**
+   * Reads a numerical ID from the stream, returning
+   * the actual ID associated with it
+   *
+   * @returns the object id
+   * @throws IOException for any errors reading from the stream
+   * @throws InvaildObjectException if ID is not found
+   */
+  public ObjectId readId (DataInputStream is)
+    throws IOException, InvalidObjectException
+  {
+    // All IDs are longs, making this really easy
+    long nid = is.readLong ();
+    return get (nid);
+  }
+
+  /**
+   * Gets the reference type id for the given class, creating
+   * a new one if it does not already have an id
+   *
+   * @param theClazz  the class for which to get an ID
+   * @returns  the ID of the class
+   */
+  public ReferenceTypeId getReferenceTypeId (Class clazz)
+  {
+    ReferenceTypeId id = (ReferenceTypeId)_classTable.get (clazz);
+    if (id == null)
+      {
+	// Object not found. Make new id for it
+	id = JdwpIdFactory.newReferenceTypeId (clazz);
+	_classTable.put (clazz, id);
+	_ridTable.put (new Long (id.getId ()),
+		       new WeakReference (id, _ridRefQueue));
+      }
+
+    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
+  {
+    WeakReference ref = (WeakReference) _ridTable.get (new Long (id));
+    ReferenceTypeId rid = (ReferenceTypeId) ref.get ();
+    if (rid == null)
+      throw new InvalidClassException (id);
+ 
+    return rid;
+  }
+
+  /**
+   * Reads a numerical ID from the stream, returning
+   * the actual reference type ID associated with it
+   *
+   * @returns the JdwpId
+   * @throws IOException for any errors reading from the stream
+   * @throws InvaildObjectException if ID is not found
+   */
+  public ReferenceTypeId readReferenceTypeId (DataInputStream is)
+    throws IOException, InvalidClassException
+  {
+    // All IDs are longs, making this really easy
+    long nid = is.readLong ();
+    return getReferenceType (nid);
+  }
+}
_______________________________________________
Classpath-patches mailing list
Classpath-patches@gnu.org
http://lists.gnu.org/mailman/listinfo/classpath-patches

Reply via email to