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
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;
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;
81 object_list
*ptr
= &hash
[index
];
82 if (ptr
->reference
== key
)
84 else if (ptr
->reference
== NULL
)
86 if (deleted_index
== -1)
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
);
104 hash
= (object_list
*) _Jv_Malloc (hash_size
* sizeof (object_list
));
105 memset (hash
, 0, hash_size
* sizeof (object_list
));
109 object_list
*old
= hash
;
113 hash
= (object_list
*) _Jv_Malloc (hash_size
* sizeof (object_list
));
114 memset (hash
, 0, hash_size
* sizeof (object_list
));
118 if (old
[i
].reference
== NULL
|| old
[i
].weight
== DELETED
)
120 object_list
*newslot
= find_slot (old
[i
].reference
);
128 // Remove a Reference.
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
;
138 while (head
&& head
->reference
!= ref
)
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?
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.
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
)
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
;
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
;
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
))
190 else if (java::lang::ref::WeakReference::class$
.isInstance (the_reference
))
194 object_list
**link
= &item
->next
;
195 object_list
*iter
= *link
;
196 while (iter
&& iter
->weight
< n
->weight
)
205 // This is called when an object is ready to be finalized. This
206 // actually implements the appropriate Reference semantics.
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
;
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
220 list
->weight
= DELETED
;
225 enum weight w
= head
->weight
;
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
);
235 _Jv_FinalizeObject (obj
);
236 list
->next
= head
->next
;
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.
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
)
255 object_list
*next
= head
->next
;
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.
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
);
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
);
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
);