Merge from mainline.
[official-gcc.git] / libjava / classpath / vm / reference / gnu / classpath / jdwp / VMIdManager.java
blob8d423e9b0d66a2a44cd4d0e6a61c59e130878498
1 /* VMIdManager.java -- A reference/example implementation of a manager for
2 JDWP object/reference type IDs
4 Copyright (C) 2005, 2006 Free Software Foundation
6 This file is part of GNU Classpath.
8 GNU Classpath is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 GNU Classpath is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Classpath; see the file COPYING. If not, write to the
20 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301 USA.
23 Linking this library statically or dynamically with other modules is
24 making a combined work based on this library. Thus, the terms and
25 conditions of the GNU General Public License cover the whole
26 combination.
28 As a special exception, the copyright holders of this library give you
29 permission to link this library with independent modules to produce an
30 executable, regardless of the license terms of these independent
31 modules, and to copy and distribute the resulting executable under
32 terms of your choice, provided that you also meet, for each linked
33 terms of your choice, provided that you also meet, for each linked
34 independent module, the terms and conditions of the license of that
35 module. An independent module is a module which is not derived from
36 or based on this library. If you modify this library, you may extend
37 this exception to your version of the library, but you are not
38 obligated to do so. If you do not wish to do so, delete this
39 exception statement from your version. */
42 package gnu.classpath.jdwp;
44 import gnu.classpath.jdwp.exception.InvalidClassException;
45 import gnu.classpath.jdwp.exception.InvalidObjectException;
46 import gnu.classpath.jdwp.id.*;
48 import java.lang.ref.Reference;
49 import java.lang.ref.ReferenceQueue;
50 import java.lang.ref.SoftReference;
51 import java.nio.ByteBuffer;
52 import java.util.HashMap;
53 import java.util.Hashtable;
55 /**
56 * This class manages objects and referencetypes that are reported
57 * to the debugger. All objects and referencetypes reported to the
58 * debugger should go through this manager.
60 * A brief summary of what an <code>IdManager</code> must provide:
62 * <code>
63 * public ObjectId getObjectId (Object theObject);
64 * public ObjectId get (long id);
65 * public ObjectId readObjectId (ByteBuffer bb);
66 * public ReferenceTypeId getReferenceTypeId (Class clazz);
67 * public ReferenceTypeId getReferenceType (long id);
68 * public ReferenceTypeId readReferenceTypeId (ByteBuffer bb);
69 * </code>
71 * See the javadoc on these methods later in this file for more
72 * information on these functions.
74 * <b>NOTE:</b> All IDs handled by the ID manager (all object and reference
75 * type IDs) are assumed to be of type <code>long</code>.
77 * <b>NOTE:</b> This class does not manage virtual machine-specific types,
78 * like methods, fields, and frames. These already have unique IDs within
79 * the virtual machine and do not need further abstraction here.
81 * @author Keith Seitz (keiths@redhat.com)
83 public class VMIdManager
85 // This factory generates ids for objects and types that may
86 // be sent to a debugger.
87 private static class IdFactory
89 // ID of last object / referencetype
90 private static Object _idLock = new Object ();
91 private static Object _ridLock = new Object ();
92 private static long _lastId = 0;
93 private static long _lastRid = 0;
95 // A list of all ID types
96 private static HashMap _idList = new HashMap ();
98 // Initialize the id list with known types
99 static
101 // ObjectId and ArrayId are special cases. See newObjectId.
102 _idList.put (ClassLoaderId.typeClass, ClassLoaderId.class);
103 _idList.put (ClassObjectId.typeClass, ClassObjectId.class);
104 _idList.put (StringId.typeClass, StringId.class);
105 _idList.put (ThreadId.typeClass, ThreadId.class);
106 _idList.put (ThreadGroupId.typeClass, ThreadGroupId.class);
110 * Returns a new id for the given object
112 * @param obj SoftReference of the object for which an id is desired
113 * @returns a suitable object id
115 public static ObjectId newObjectId (SoftReference obj)
117 ObjectId id = null;
118 Object object = obj.get ();
120 // Special case: arrays
121 if (object.getClass ().isArray ())
122 id = new ArrayId ();
123 else
125 // Loop through all classes until we hit baseclass
126 Class myClass;
127 for (myClass = object.getClass (); myClass != null;
128 myClass = myClass.getSuperclass ())
130 Class clz = (Class) _idList.get (myClass);
131 if (clz != null)
135 id = (ObjectId) clz.newInstance ();
136 synchronized (_idLock)
138 id.setId (++_lastId);
140 id.setReference (obj);
141 return id;
143 catch (InstantiationException ie)
145 // This really should not happen
146 throw new RuntimeException ("cannot create new ID", ie);
148 catch (IllegalAccessException iae)
150 // This really should not happen
151 throw new RuntimeException ("illegal access of ID", iae);
156 /* getSuperclass returned null and no matching ID type found.
157 So it must derive from Object. */
158 id = new ObjectId ();
161 synchronized (_idLock)
163 id.setId (++_lastId);
165 id.setReference (obj);
166 return id;
170 * Returns a new reference type id for the given class
172 * @param ref SoftReference to the desired type
173 * @returns a suitable reference type id or null when the
174 * reference is cleared.
176 public static ReferenceTypeId newReferenceTypeId (SoftReference ref)
178 ReferenceTypeId id;
179 Class clazz = (Class) ref.get ();
180 if (clazz == null)
181 return null;
183 if (clazz.isArray ())
184 id = new ArrayReferenceTypeId ();
185 else if (clazz.isInterface ())
186 id = new InterfaceReferenceTypeId ();
187 else
188 id = new ClassReferenceTypeId ();
189 id.setReference (ref);
190 synchronized (_ridLock)
192 id.setId (++_lastRid);
194 return id;
199 * This class is a SoftReferenceIdentity type that is used by
200 * the ID manager.
202 class ReferenceKey extends SoftReference
204 // Hash code of referent
205 private int _hash;
208 * Constructs a new <code>ReferenceKey</code> object
209 * with the given referent.
211 * <p>This constructor should only be used for object lookups
212 * by the backend.
214 * @param referent the object to reference
216 public ReferenceKey (Object referent)
218 super (referent);
219 _hash = referent.hashCode ();
223 * Constructs a new <code>ReferenceKey</code> object
224 * with the given referent and reference queue.
226 * <p>The JDWP back-end stores a <code>ReferenceKey</code>
227 * with its corresponding <code>JdwpId</code>. This constructor
228 * is used by the back-end when adding new IDs to be managed.
230 * @param referent the object to reference
231 * @param queue the queue to which to report garbage collections
233 public ReferenceKey (Object referent, ReferenceQueue queue)
235 super (referent, queue);
236 _hash = referent.hashCode ();
240 * Returns the hash code of the referent.
241 * This seems hacky, but is required in order to use this class
242 * as a hash table key.
244 * @returns the hash code of the referent
246 public int hashCode ()
248 return _hash;
252 * Comparator for keys
254 * This method can be used in two ways:
256 * <ol>
257 * <li>For table lookups, where we want to compare referents</li>
258 * <li>For clearing GCd objects, where we want to compare the actual
259 * key object (not the referent)</li>
260 * </ol>
262 public boolean equals (Object obj)
264 if (obj instanceof ReferenceKey)
266 ReferenceKey ref = (ReferenceKey) obj;
268 /* First check if the two references are the same.
269 If they are, that means we must be clearing GCd objects. */
270 if (this == obj)
271 return true;
273 return (ref.get () == get ());
276 return false;
280 // instance of VMIdManager
281 private static VMIdManager _idm = new VMIdManager ();
283 // A reference queue for our objects
284 private ReferenceQueue _refQueue;
286 // Mapping of objects (ReferenceKey) to IDs (ObjectId)
287 private Hashtable _oidTable;
289 // Mapping of ID numbers (Long) to IDs (ObjectId)
290 private Hashtable _idTable;
292 /* Mapping of class (ReferenceKey) to IDs (ReferenceTypeId) for reference
293 types. Unlike other types, reference id types are NEVER released. */
294 private Hashtable _classTable;
296 // Mapping of ID numbers (Long) to reference type IDs (ReferenceTypeId)
297 private Hashtable _ridTable;
300 * Gets the instance of VMIdManager, constructing a new one
301 * if none currently exists.
303 public static VMIdManager getDefault ()
305 return _idm;
308 // Constructs a new <code>IdManager</code>
309 private VMIdManager ()
311 _refQueue = new ReferenceQueue ();
312 _oidTable = new Hashtable (50);
313 _idTable = new Hashtable (50);
314 _classTable = new Hashtable (20);
315 _ridTable = new Hashtable (20);
318 // Updates the object ID table, removing IDs whose objects have
319 // been garbage collected.
320 private void _update ()
322 Reference ref;
323 while ((ref = _refQueue.poll ()) != null)
325 ObjectId id = (ObjectId) _oidTable.get (ref);
326 _oidTable.remove (ref);
327 _idTable.remove (new Long (id.getId ()));
332 * Returns an id for the given object, adding it
333 * if it does not have an id.
335 * @param theObject the object to get an ID/add
336 * @returns the ID of the object
338 public ObjectId getObjectId (Object theObject)
340 ReferenceKey ref = new ReferenceKey (theObject, _refQueue);
341 ObjectId id = (ObjectId) _oidTable.get (ref);
342 if (id == null)
344 // update the tables -- this is an arbitrary place to put this
345 _update ();
347 // Object not found. Make new id for it
348 id = IdFactory.newObjectId (ref);
349 _oidTable.put (ref, id);
350 _idTable.put (new Long (id.getId ()), id);
353 return id;
357 * Returns the <code>JdwpId</code> for a given ID. Unlike
358 * <code>getId</code>, it throws an exception if the ID is not
359 * known.
361 * @param id the numerical ID of the desired <code>JdwpId</code>
362 * @throws InvalidObjectException if the ID is not found
364 public ObjectId get (long id)
365 throws InvalidObjectException
367 ObjectId oid = (ObjectId) _idTable.get (new Long (id));
368 if (oid == null)
369 throw new InvalidObjectException (id);
371 return oid;
374 public ObjectId readObjectId (ByteBuffer bb)
375 throws InvalidObjectException
377 long id = bb.getLong ();
378 return get (id);
382 * Gets the reference type id for the given class, creating
383 * a new one if it does not already have an id
385 * @param clazz the class for which to get an ID
386 * @returns the ID of the class
388 public ReferenceTypeId getReferenceTypeId (Class clazz)
390 ReferenceKey ref = new ReferenceKey (clazz);
391 ReferenceTypeId id = (ReferenceTypeId)_classTable.get (ref);
392 if (id == null)
394 // Object not found. Make new id for it
395 id = IdFactory.newReferenceTypeId (ref);
396 _classTable.put (ref, id);
397 _ridTable.put (new Long (id.getId ()), id);
400 return id;
404 * Returns the <code>ReferenceTypeId</code> for a given ID. Unlike
405 * <code>getReferenceTypeId</code>, it throws an exception if the ID is not
406 * known.
408 * @param id the numerical ID of the desired reference type
409 * @throws InvalidClassException if the ID is not found
411 public ReferenceTypeId getReferenceType (long id)
412 throws InvalidClassException
414 ReferenceTypeId rid = (ReferenceTypeId) _ridTable.get (new Long (id));
415 if (rid == null)
416 throw new InvalidClassException (id);
418 return rid;
421 public ReferenceTypeId readReferenceTypeId (ByteBuffer bb)
422 throws InvalidClassException
424 long id = bb.getLong ();
425 return getReferenceType (id);