FSF GCC merge 02/23/03
[official-gcc.git] / libjava / java / lang / ref / natReference.cc
blob64262f900cbe59160322833b93b222ed47b90712
1 // natReference.cc - Native code for References
3 /* Copyright (C) 2001, 2002 Free Software Foundation
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 details. */
11 // Written by Tom Tromey <tromey@redhat.com>
13 #include <config.h>
15 #include <gcj/cni.h>
16 #include <jvm.h>
17 #include <java/lang/Throwable.h>
18 #include <java/lang/ref/Reference.h>
19 #include <java/lang/ref/SoftReference.h>
20 #include <java/lang/ref/WeakReference.h>
21 #include <java/lang/ref/PhantomReference.h>
22 #include <java/lang/ref/ReferenceQueue.h>
24 static void finalize_reference (jobject ref);
25 static void finalize_referred_to_object (jobject obj);
29 enum weight
31 SOFT = 0,
32 WEAK = 1,
33 FINALIZE = 2,
34 PHANTOM = 3,
36 // This is used to mark the head of a list.
37 HEAD = 4,
39 // This is used to mark a deleted item.
40 DELETED = 5
43 // Objects of this type are used in the hash table to keep track of
44 // the mapping between a finalizable object and the various References
45 // which refer to it.
46 struct object_list
48 // The reference object. This is NULL for FINALIZE weight.
49 jobject reference;
51 // The weight of this object.
52 enum weight weight;
54 // Next in list.
55 object_list *next;
58 // Hash table used to hold mapping from object to References. The
59 // object_list item in the hash holds the object itself in the
60 // reference field; chained to it are all the references sorted in
61 // order of weight (lowest first).
62 static object_list *hash = NULL;
64 // Number of slots used in HASH.
65 static int hash_count = 0;
67 // Number of slots total in HASH. Must be power of 2.
68 static int hash_size = 0;
70 static object_list *
71 find_slot (jobject key)
73 jint hcode = _Jv_HashCode (key);
74 /* step must be non-zero, and relatively prime with hash_size. */
75 jint step = (hcode ^ (hcode >> 16)) | 1;
76 int start_index = hcode & (hash_size - 1);
77 int index = start_index;
78 int deleted_index = -1;
79 for (;;)
81 object_list *ptr = &hash[index];
82 if (ptr->reference == key)
83 return ptr;
84 else if (ptr->reference == NULL)
86 if (deleted_index == -1)
87 return ptr;
88 else
89 return &hash[deleted_index];
91 else if (ptr->weight == DELETED)
92 deleted_index = index;
93 index = (index + step) & (hash_size - 1);
94 JvAssert (index != start_index);
98 static void
99 rehash ()
101 if (hash == NULL)
103 hash_size = 1024;
104 hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list));
105 memset (hash, 0, hash_size * sizeof (object_list));
107 else
109 object_list *old = hash;
110 int i = hash_size;
112 hash_size *= 2;
113 hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list));
114 memset (hash, 0, hash_size * sizeof (object_list));
116 while (--i >= 0)
118 if (old[i].reference == NULL || old[i].weight == DELETED)
119 continue;
120 object_list *newslot = find_slot (old[i].reference);
121 *newslot = old[i];
124 _Jv_Free (old);
128 // Remove a Reference.
129 static void
130 remove_from_hash (jobject obj)
132 java::lang::ref::Reference *ref
133 = reinterpret_cast<java::lang::ref::Reference *> (obj);
134 object_list *head = find_slot (ref->copy);
135 object_list **link = &head->next;
136 head = head->next;
138 while (head && head->reference != ref)
140 link = &head->next;
141 head = head->next;
144 // Remove the slot.
145 if (head)
147 *link = head->next;
148 _Jv_Free (head);
152 // FIXME what happens if an object's finalizer creates a Reference to
153 // the object, and the object has never before been added to the hash?
154 // Madness!
156 // Add an item to the hash table. If the item is new, we also add a
157 // finalizer item. We keep items in the hash table until they are
158 // completely collected; this lets us know when an item is new, even
159 // if it has been resurrected after its finalizer has been run.
160 static void
161 add_to_hash (java::lang::ref::Reference *the_reference)
163 JvSynchronize sync (java::lang::ref::Reference::lock);
165 if (3 * hash_count >= 2 * hash_size)
166 rehash ();
168 // Use `copy' here because the `referent' field has been cleared.
169 jobject referent = the_reference->copy;
170 object_list *item = find_slot (referent);
171 if (item->reference == NULL)
173 // New item, so make an entry for the finalizer.
174 item->reference = referent;
175 item->weight = HEAD;
177 item->next = (object_list *) _Jv_Malloc (sizeof (object_list));
178 item->next->reference = NULL;
179 item->next->weight = FINALIZE;
180 item->next->next = NULL;
181 ++hash_count;
184 object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list));
185 n->reference = the_reference;
187 enum weight w = PHANTOM;
188 if (java::lang::ref::SoftReference::class$.isInstance (the_reference))
189 w = SOFT;
190 else if (java::lang::ref::WeakReference::class$.isInstance (the_reference))
191 w = WEAK;
192 n->weight = w;
194 object_list **link = &item->next;
195 object_list *iter = *link;
196 while (iter && iter->weight < n->weight)
198 link = &iter->next;
199 iter = *link;
201 n->next = *link;
202 *link = n;
205 // This is called when an object is ready to be finalized. This
206 // actually implements the appropriate Reference semantics.
207 static void
208 finalize_referred_to_object (jobject obj)
210 JvSynchronize sync (java::lang::ref::Reference::lock);
212 object_list *list = find_slot (obj);
213 object_list *head = list->next;
214 if (head == NULL)
216 // We have a truly dead object: the object's finalizer has been
217 // run, all the object's references have been processed, and the
218 // object is unreachable. There is, at long last, no way to
219 // resurrect it.
220 list->weight = DELETED;
221 --hash_count;
222 return;
225 enum weight w = head->weight;
226 if (w == FINALIZE)
228 // If we have a Reference A to a Reference B, and B is
229 // finalized, then we have to take special care to make sure
230 // that B is properly deregistered. This is super gross. FIXME
231 // will it fail if B's finalizer resurrects B?
232 if (java::lang::ref::Reference::class$.isInstance (obj))
233 finalize_reference (obj);
234 else
235 _Jv_FinalizeObject (obj);
236 list->next = head->next;
237 _Jv_Free (head);
239 else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj))
241 // If we just decided to reclaim a soft reference, we might as
242 // well do all the weak references at the same time.
243 if (w == SOFT)
244 w = WEAK;
246 while (head && head->weight <= w)
248 java::lang::ref::Reference *ref
249 = reinterpret_cast<java::lang::ref::Reference *> (head->reference);
250 // If the copy is already NULL then the user must have
251 // called Reference.clear().
252 if (ref->copy != NULL)
253 ref->enqueue ();
255 object_list *next = head->next;
256 _Jv_Free (head);
257 head = next;
259 list->next = head;
262 // Re-register this finalizer. We always re-register because we
263 // can't know until the next collection cycle whether or not the
264 // object is truly unreachable.
265 _Jv_RegisterFinalizer (obj, finalize_referred_to_object);
268 // This is called when a Reference object is finalized. If there is a
269 // Reference pointing to this Reference then that case is handled by
270 // finalize_referred_to_object.
271 static void
272 finalize_reference (jobject ref)
274 JvSynchronize sync (java::lang::ref::Reference::lock);
275 remove_from_hash (ref);
276 // The user might have a subclass of Reference with a finalizer.
277 _Jv_FinalizeObject (ref);
280 void
281 ::java::lang::ref::Reference::create (jobject ref)
283 // Nothing says you can't make a Reference with a NULL referent.
284 // But there's nothing to do in such a case.
285 referent = reinterpret_cast<gnu::gcj::RawData *> (ref);
286 copy = referent;
287 if (referent != NULL)
289 JvSynchronize sync (java::lang::ref::Reference::lock);
290 // `this' is a new Reference object. We register a new
291 // finalizer for pointed-to object and we arrange a special
292 // finalizer for ourselves as well.
293 _Jv_RegisterFinalizer (this, finalize_reference);
294 _Jv_RegisterFinalizer (referent, finalize_referred_to_object);
295 jobject *objp = reinterpret_cast<jobject *> (&referent);
296 _Jv_GCRegisterDisappearingLink (objp);
297 add_to_hash (this);