1 // natReference.cc - Native code for References
3 /* Copyright (C) 2001, 2002, 2003 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
11 // Written by Tom Tromey <tromey@redhat.com>
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
);
36 // This is used to mark the head of a list.
39 // This is used to mark a deleted item.
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
48 // The reference object. This is NULL for FINALIZE weight.
51 // The weight of this object.
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 #define DELETED_REFERENCE ((jobject) -1)
73 find_slot (jobject key
)
75 jint hcode
= _Jv_HashCode (key
);
76 /* step must be non-zero, and relatively prime with hash_size. */
77 jint step
= (hcode
^ (hcode
>> 16)) | 1;
78 int start_index
= hcode
& (hash_size
- 1);
79 int index
= start_index
;
80 int deleted_index
= -1;
83 object_list
*ptr
= &hash
[index
];
84 if (ptr
->reference
== key
)
86 else if (ptr
->reference
== NULL
)
88 if (deleted_index
== -1)
91 return &hash
[deleted_index
];
93 else if (ptr
->weight
== DELETED
)
95 deleted_index
= index
;
96 JvAssert (ptr
->reference
== DELETED_REFERENCE
);
98 index
= (index
+ step
) & (hash_size
- 1);
99 JvAssert (index
!= start_index
);
109 hash
= (object_list
*) _Jv_Malloc (hash_size
* sizeof (object_list
));
110 memset (hash
, 0, hash_size
* sizeof (object_list
));
114 object_list
*old
= hash
;
118 hash
= (object_list
*) _Jv_Malloc (hash_size
* sizeof (object_list
));
119 memset (hash
, 0, hash_size
* sizeof (object_list
));
123 if (old
[i
].reference
== NULL
|| old
[i
].weight
== DELETED
)
125 object_list
*newslot
= find_slot (old
[i
].reference
);
133 // Remove a Reference.
135 remove_from_hash (jobject obj
)
137 java::lang::ref::Reference
*ref
138 = reinterpret_cast<java::lang::ref::Reference
*> (obj
);
139 object_list
*head
= find_slot (ref
->copy
);
141 // We might have found a new slot. We can just ignore that here.
142 if (head
->reference
!= ref
->copy
)
145 object_list
**link
= &head
->next
;
148 while (head
&& head
->reference
!= ref
)
162 // Return list head if object is in hash, NULL otherwise.
164 in_hash (jobject obj
)
166 // The hash table might not yet be initialized.
169 object_list
*head
= find_slot (obj
);
170 if (head
->reference
!= obj
)
175 // FIXME what happens if an object's finalizer creates a Reference to
176 // the object, and the object has never before been added to the hash?
179 // Add an item to the hash table. If the item is new, we also add a
180 // finalizer item. We keep items in the hash table until they are
181 // completely collected; this lets us know when an item is new, even
182 // if it has been resurrected after its finalizer has been run.
184 add_to_hash (java::lang::ref::Reference
*the_reference
)
186 JvSynchronize
sync (java::lang::ref::Reference::lock
);
188 if (3 * hash_count
>= 2 * hash_size
)
191 // Use `copy' here because the `referent' field has been cleared.
192 jobject referent
= the_reference
->copy
;
193 object_list
*item
= find_slot (referent
);
194 if (item
->reference
== NULL
|| item
->reference
== DELETED_REFERENCE
)
196 // New item, so make an entry for the finalizer.
197 item
->reference
= referent
;
200 item
->next
= (object_list
*) _Jv_Malloc (sizeof (object_list
));
201 item
->next
->reference
= NULL
;
202 item
->next
->weight
= FINALIZE
;
203 item
->next
->next
= NULL
;
207 object_list
*n
= (object_list
*) _Jv_Malloc (sizeof (object_list
));
208 n
->reference
= the_reference
;
210 enum weight w
= PHANTOM
;
211 if (java::lang::ref::SoftReference::class$
.isInstance (the_reference
))
213 else if (java::lang::ref::WeakReference::class$
.isInstance (the_reference
))
217 object_list
**link
= &item
->next
;
218 object_list
*iter
= *link
;
219 while (iter
&& iter
->weight
< n
->weight
)
228 // Add a FINALIZE entry if one doesn't exist.
230 maybe_add_finalize (object_list
*entry
, jobject obj
)
232 object_list
**link
= &entry
->next
;
233 object_list
*iter
= *link
;
234 while (iter
&& iter
->weight
< FINALIZE
)
240 // We want at most one FINALIZE entry in the queue.
241 if (iter
&& iter
->weight
== FINALIZE
)
244 object_list
*n
= (object_list
*) _Jv_Malloc (sizeof (object_list
));
246 n
->weight
= FINALIZE
;
251 // This is called when an object is ready to be finalized. This
252 // actually implements the appropriate Reference semantics.
254 finalize_referred_to_object (jobject obj
)
256 JvSynchronize
sync (java::lang::ref::Reference::lock
);
258 object_list
*list
= find_slot (obj
);
259 object_list
*head
= list
->next
;
262 // We have a truly dead object: the object's finalizer has been
263 // run, all the object's references have been processed, and the
264 // object is unreachable. There is, at long last, no way to
266 list
->reference
= DELETED_REFERENCE
;
267 list
->weight
= DELETED
;
272 enum weight w
= head
->weight
;
275 // Update the list first, as _Jv_FinalizeString might end up
276 // looking at this data structure.
277 list
->next
= head
->next
;
280 // If we have a Reference A to a Reference B, and B is
281 // finalized, then we have to take special care to make sure
282 // that B is properly deregistered. This is super gross. FIXME
283 // will it fail if B's finalizer resurrects B?
284 if (java::lang::ref::Reference::class$
.isInstance (obj
))
285 finalize_reference (obj
);
286 else if (obj
->getClass() == &java::lang::String::class$
)
287 _Jv_FinalizeString (obj
);
289 _Jv_FinalizeObject (obj
);
291 else if (w
!= SOFT
|| _Jv_GCCanReclaimSoftReference (obj
))
293 // If we just decided to reclaim a soft reference, we might as
294 // well do all the weak references at the same time.
298 while (head
&& head
->weight
<= w
)
300 java::lang::ref::Reference
*ref
301 = reinterpret_cast<java::lang::ref::Reference
*> (head
->reference
);
305 object_list
*next
= head
->next
;
312 // Re-register this finalizer. We always re-register because we
313 // can't know until the next collection cycle whether or not the
314 // object is truly unreachable.
315 _Jv_RegisterFinalizer (obj
, finalize_referred_to_object
);
318 // This is called when a Reference object is finalized. If there is a
319 // Reference pointing to this Reference then that case is handled by
320 // finalize_referred_to_object.
322 finalize_reference (jobject ref
)
324 JvSynchronize
sync (java::lang::ref::Reference::lock
);
325 remove_from_hash (ref
);
326 // The user might have a subclass of Reference with a finalizer.
327 _Jv_FinalizeObject (ref
);
331 _Jv_RegisterStringFinalizer (jobject str
)
333 // This function might be called before any other Reference method,
334 // so we must ensure the class is initialized.
335 _Jv_InitClass (&java::lang::ref::Reference::class$
);
336 JvSynchronize
sync (java::lang::ref::Reference::lock
);
337 // If the object is in our hash table, then we might need to add a
338 // new FINALIZE entry. Otherwise, we just register an ordinary
340 object_list
*entry
= in_hash (str
);
342 maybe_add_finalize (entry
, str
);
344 _Jv_RegisterFinalizer ((void *) str
, _Jv_FinalizeString
);
348 ::java::lang::ref::Reference::create (jobject ref
)
350 // Nothing says you can't make a Reference with a NULL referent.
351 // But there's nothing to do in such a case.
352 referent
= reinterpret_cast<gnu::gcj::RawData
*> (ref
);
354 if (referent
!= NULL
)
356 JvSynchronize
sync (java::lang::ref::Reference::lock
);
357 // `this' is a new Reference object. We register a new
358 // finalizer for pointed-to object and we arrange a special
359 // finalizer for ourselves as well.
360 _Jv_RegisterFinalizer (this, finalize_reference
);
361 _Jv_RegisterFinalizer (referent
, finalize_referred_to_object
);
362 jobject
*objp
= reinterpret_cast<jobject
*> (&referent
);
363 _Jv_GCRegisterDisappearingLink (objp
);