source: trunk/gcc/libjava/java/lang/ref/natReference.cc

Last change on this file was 1392, checked in by bird, 21 years ago

This commit was generated by cvs2svn to compensate for changes in r1391,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 8.1 KB
Line 
1// natReference.cc - Native code for References
2
3/* Copyright (C) 2001, 2002 Free Software Foundation
4
5 This file is part of libgcj.
6
7This software is copyrighted work licensed under the terms of the
8Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9details. */
10
11// Written by Tom Tromey <tromey@redhat.com>
12
13#include <config.h>
14
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>
23
24static void finalize_reference (jobject ref);
25static void finalize_referred_to_object (jobject obj);
26
27
28
29
30enum weight
31{
32 SOFT = 0,
33 WEAK = 1,
34 FINALIZE = 2,
35 PHANTOM = 3,
36
37 // This is used to mark the head of a list.
38 HEAD = 4,
39
40 // This is used to mark a deleted item.
41 DELETED = 5
42};
43
44// Objects of this type are used in the hash table to keep track of
45// the mapping between a finalizable object and the various References
46// which refer to it.
47struct object_list
48{
49 // The reference object. This is NULL for FINALIZE weight.
50 jobject reference;
51
52 // The weight of this object.
53 enum weight weight;
54
55 // Next in list.
56 object_list *next;
57};
58
59// Hash table used to hold mapping from object to References. The
60// object_list item in the hash holds the object itself in the
61// reference field; chained to it are all the references sorted in
62// order of weight (lowest first).
63static object_list *hash = NULL;
64
65// Number of slots used in HASH.
66static int hash_count = 0;
67
68// Number of slots total in HASH. Must be power of 2.
69static int hash_size = 0;
70
71static object_list *
72find_slot (jobject key)
73{
74 jint hcode = _Jv_HashCode (key);
75 /* step must be non-zero, and relatively prime with hash_size. */
76 jint step = (hcode ^ (hcode >> 16)) | 1;
77 int start_index = hcode & (hash_size - 1);
78 int index = start_index;
79 int deleted_index = -1;
80 for (;;)
81 {
82 object_list *ptr = &hash[index];
83 if (ptr->reference == key)
84 return ptr;
85 else if (ptr->reference == NULL)
86 {
87 if (deleted_index == -1)
88 return ptr;
89 else
90 return &hash[deleted_index];
91 }
92 else if (ptr->weight == DELETED)
93 deleted_index = index;
94 index = (index + step) & (hash_size - 1);
95 JvAssert (index != start_index);
96 }
97}
98
99static void
100rehash ()
101{
102 if (hash == NULL)
103 {
104 hash_size = 1024;
105 hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list));
106 memset (hash, 0, hash_size * sizeof (object_list));
107 }
108 else
109 {
110 object_list *old = hash;
111 int i = hash_size;
112
113 hash_size *= 2;
114 hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list));
115 memset (hash, 0, hash_size * sizeof (object_list));
116
117 while (--i >= 0)
118 {
119 if (old[i].reference == NULL || old[i].weight == DELETED)
120 continue;
121 object_list *newslot = find_slot (old[i].reference);
122 *newslot = old[i];
123 }
124
125 _Jv_Free (old);
126 }
127}
128
129// Remove a Reference.
130static void
131remove_from_hash (jobject obj)
132{
133 java::lang::ref::Reference *ref
134 = reinterpret_cast<java::lang::ref::Reference *> (obj);
135 object_list *head = find_slot (ref->copy);
136 object_list **link = &head->next;
137 head = head->next;
138
139 while (head && head->reference != ref)
140 {
141 link = &head->next;
142 head = head->next;
143 }
144
145 // Remove the slot.
146 if (head)
147 {
148 *link = head->next;
149 _Jv_Free (head);
150 }
151}
152
153// FIXME what happens if an object's finalizer creates a Reference to
154// the object, and the object has never before been added to the hash?
155// Madness!
156
157// Add an item to the hash table. If the item is new, we also add a
158// finalizer item. We keep items in the hash table until they are
159// completely collected; this lets us know when an item is new, even
160// if it has been resurrected after its finalizer has been run.
161static void
162add_to_hash (java::lang::ref::Reference *the_reference)
163{
164 JvSynchronize sync (java::lang::ref::Reference::lock);
165
166 if (3 * hash_count >= 2 * hash_size)
167 rehash ();
168
169 // Use `copy' here because the `referent' field has been cleared.
170 jobject referent = the_reference->copy;
171 object_list *item = find_slot (referent);
172 if (item->reference == NULL)
173 {
174 // New item, so make an entry for the finalizer.
175 item->reference = referent;
176 item->weight = HEAD;
177
178 item->next = (object_list *) _Jv_Malloc (sizeof (object_list));
179 item->next->reference = NULL;
180 item->next->weight = FINALIZE;
181 item->next->next = NULL;
182 ++hash_count;
183 }
184
185 object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list));
186 n->reference = the_reference;
187
188 enum weight w = PHANTOM;
189 if (java::lang::ref::SoftReference::class$.isInstance (the_reference))
190 w = SOFT;
191 else if (java::lang::ref::WeakReference::class$.isInstance (the_reference))
192 w = WEAK;
193 n->weight = w;
194
195 object_list **link = &item->next;
196 object_list *iter = *link;
197 while (iter && iter->weight < n->weight)
198 {
199 link = &iter->next;
200 iter = *link;
201 }
202 n->next = *link;
203 *link = n;
204}
205
206// This is called when an object is ready to be finalized. This
207// actually implements the appropriate Reference semantics.
208static void
209finalize_referred_to_object (jobject obj)
210{
211 JvSynchronize sync (java::lang::ref::Reference::lock);
212
213 object_list *list = find_slot (obj);
214 object_list *head = list->next;
215 if (head == NULL)
216 {
217 // We have a truly dead object: the object's finalizer has been
218 // run, all the object's references have been processed, and the
219 // object is unreachable. There is, at long last, no way to
220 // resurrect it.
221 list->weight = DELETED;
222 --hash_count;
223 return;
224 }
225
226 enum weight w = head->weight;
227 if (w == FINALIZE)
228 {
229 // If we have a Reference A to a Reference B, and B is
230 // finalized, then we have to take special care to make sure
231 // that B is properly deregistered. This is super gross. FIXME
232 // will it fail if B's finalizer resurrects B?
233 if (java::lang::ref::Reference::class$.isInstance (obj))
234 finalize_reference (obj);
235 else
236 _Jv_FinalizeObject (obj);
237 list->next = head->next;
238 _Jv_Free (head);
239 }
240 else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj))
241 {
242 // If we just decided to reclaim a soft reference, we might as
243 // well do all the weak references at the same time.
244 if (w == SOFT)
245 w = WEAK;
246
247 while (head && head->weight <= w)
248 {
249 java::lang::ref::Reference *ref
250 = reinterpret_cast<java::lang::ref::Reference *> (head->reference);
251 // If the copy is already NULL then the user must have
252 // called Reference.clear().
253 if (ref->copy != NULL)
254 ref->enqueue ();
255
256 object_list *next = head->next;
257 _Jv_Free (head);
258 head = next;
259 }
260 list->next = head;
261 }
262
263 // Re-register this finalizer. We always re-register because we
264 // can't know until the next collection cycle whether or not the
265 // object is truly unreachable.
266 _Jv_RegisterFinalizer (obj, finalize_referred_to_object);
267}
268
269// This is called when a Reference object is finalized. If there is a
270// Reference pointing to this Reference then that case is handled by
271// finalize_referred_to_object.
272static void
273finalize_reference (jobject ref)
274{
275 JvSynchronize sync (java::lang::ref::Reference::lock);
276 remove_from_hash (ref);
277 // The user might have a subclass of Reference with a finalizer.
278 _Jv_FinalizeObject (ref);
279}
280
281void
282::java::lang::ref::Reference::create (jobject ref)
283{
284 // Nothing says you can't make a Reference with a NULL referent.
285 // But there's nothing to do in such a case.
286 referent = reinterpret_cast<gnu::gcj::RawData *> (ref);
287 copy = referent;
288 if (referent != NULL)
289 {
290 JvSynchronize sync (java::lang::ref::Reference::lock);
291 // `this' is a new Reference object. We register a new
292 // finalizer for pointed-to object and we arrange a special
293 // finalizer for ourselves as well.
294 _Jv_RegisterFinalizer (this, finalize_reference);
295 _Jv_RegisterFinalizer (referent, finalize_referred_to_object);
296 jobject *objp = reinterpret_cast<jobject *> (&referent);
297 _Jv_GCRegisterDisappearingLink (objp);
298 add_to_hash (this);
299 }
300}
Note: See TracBrowser for help on using the repository browser.