* src/mm/cacao-gc/gc.c (gc_reflist_weak): Added list for weak references.
[cacao.git] / src / mm / cacao-gc / mark.c
1 /* mm/cacao-gc/mark.c - GC module for marking heap objects
2
3    Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29
30 #include "gc.h"
31 #include "final.h"
32 #include "heap.h"
33 #include "mark.h"
34 #include "rootset.h"
35 #include "mm/memory.h"
36 #include "toolbox/logging.h"
37 #include "vm/global.h"
38 #include "vm/vm.h"
39 #include "vmcore/linker.h"
40
41
42 /* Helper Macros **************************************************************/
43
44 #define MARK(o) \
45         GCSTAT_COUNT_MAX(gcstat_mark_depth, gcstat_mark_depth_max); \
46         mark_recursive(o); \
47         GCSTAT_DEC(gcstat_mark_depth);
48
49
50 /* mark_recursive **************************************************************
51
52    Recursively mark all objects (including this) which are referenced.
53
54    TODO, XXX: We need to implement a non-recursive version of this!!!
55
56    IN:
57           o.....heap-object to be marked (either OBJECT or ARRAY)
58
59 *******************************************************************************/
60
61 void mark_recursive(java_object_t *o)
62 {
63         vftbl_t            *t;
64         classinfo          *c;
65         fieldinfo          *f;
66         java_objectarray_t *oa;
67         arraydescriptor    *desc;
68         java_object_t      *ref;
69         void *start, *end;
70         int i;
71
72         /* TODO: this needs cleanup!!! */
73         start = heap_region_main->base;
74         end = heap_region_main->ptr;
75
76         /* uncollectable objects should never get marked this way */
77         /* the reference should point into the heap */
78         GC_ASSERT(o);
79         GC_ASSERT(!GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE));
80         GC_ASSERT(POINTS_INTO(o, start, end));
81
82         /* mark this object */
83         GC_SET_MARKED(o);
84         GCSTAT_COUNT(gcstat_mark_count);
85
86         /* get the class of this object */
87         /* TODO: maybe we do not need this yet, look to move down! */
88         t = o->vftbl;
89         GC_ASSERT(t);
90         c = t->class;
91         GC_ASSERT(c);
92
93 #if defined(GCCONF_HDRFLAG_REFERENCING)
94         /* does this object has pointers? */
95         /* TODO: check how often this happens, maybe remove this check! */
96         if (!GC_TEST_FLAGS(o, HDRFLAG_REFERENCING))
97                 return;
98 #endif
99
100         /* check if we are marking an array */
101         if ((desc = t->arraydesc) != NULL) {
102                 /* this is an ARRAY */
103
104                 /* check if the array contains references */
105                 if (desc->arraytype != ARRAYTYPE_OBJECT)
106                         return;
107
108                 /* for object-arrays we need to check every entry */
109                 oa = (java_objectarray_t *) o;
110                 for (i = 0; i < oa->header.size; i++) {
111
112                         /* load the reference value */
113                         ref = (java_object_t *) (oa->data[i]);
114
115                         /* check for outside or null pointers */
116                         if (!POINTS_INTO(ref, start, end))
117                                 continue;
118
119                         GC_LOG2( printf("Found (%p) from Array\n", (void *) ref); );
120
121                         /* do the recursive marking */
122                         if (!GC_IS_MARKED(ref)) {
123                                 GCSTAT_COUNT_MAX(gcstat_mark_depth, gcstat_mark_depth_max);
124                                 mark_recursive(ref);
125                                 GCSTAT_DEC(gcstat_mark_depth);
126                         }
127
128                 }
129
130         } else {
131                 /* this is an OBJECT */
132
133                 /* for objects we need to check all (non-static) fields */
134                 for (; c; c = c->super) {
135                 for (i = 0; i < c->fieldscount; i++) {
136                         f = &(c->fields[i]);
137
138                         /* check if this field contains a non-static reference */
139                         if (!IS_ADR_TYPE(f->type) || (f->flags & ACC_STATIC))
140                                 continue;
141
142                         /* load the reference value */
143                         ref = *( (java_object_t **) ((s1 *) o + f->offset) );
144
145                         /* check for outside or null pointers */
146                         if (!POINTS_INTO(ref, start, end))
147                                 continue;
148
149                         GC_LOG2( printf("Found (%p) from Field ", (void *) ref);
150                                         field_print(f); printf("\n"); );
151
152                         /* do the recursive marking */
153                         if (!GC_IS_MARKED(ref)) {
154                                 GCSTAT_COUNT_MAX(gcstat_mark_depth, gcstat_mark_depth_max);
155                                 mark_recursive(ref);
156                                 GCSTAT_DEC(gcstat_mark_depth);
157                         }
158
159                 }
160                 }
161
162         }
163
164 }
165
166
167 /* mark_post *******************************************************************
168
169    Perform some post-marking cleanup tasks.
170
171    TASKS:
172       - mark unmarked objects with Finalizers
173       - clear unmarked Weak References
174
175 *******************************************************************************/
176
177 void mark_post(rootset_t *rs)
178 {
179         java_object_t      *ref;
180 #if defined(GCCONF_FINALIZER)
181         list_final_entry_t *fe;
182         u4                  f_type;
183 #endif
184         void *start, *end;
185         int i;
186
187         /* TODO: this needs cleanup!!! */
188         start = heap_region_main->base;
189         end = heap_region_main->ptr;
190
191 #if defined(GCCONF_FINALIZER)
192         /* objects with finalizers will also be marked here. if they have not been
193            marked before the finalization is triggered */
194         /* REMEMBER: all threads are stopped, so we can use unsynced access here */
195         fe = list_first_unsynced(final_list);
196         while (fe) {
197                 f_type = fe->type;
198                 ref    = fe->o;
199
200                 /* we do not care about objects which have been marked already */
201                 if (!GC_IS_MARKED(ref)) {
202
203                         switch (f_type) {
204
205                         case FINAL_REACHABLE: /* object was reachable before */
206                                 GC_LOG2( printf("Finalizer triggered for: ");
207                                                 heap_print_object(ref); printf("\n"); );
208
209                                 /* object is now reclaimable */
210                                 fe->type = FINAL_RECLAIMABLE;
211
212                                 /* notify the finalizer after collection finished */
213                                 gc_notify_finalizer = true;
214
215                                 /* keep the object alive until finalizer finishes */
216                                 MARK(ref);
217                                 break;
218
219                         case FINAL_RECLAIMABLE: /* object not yet finalized */
220                                 GC_LOG( printf("Finalizer not yet started for: ");
221                                                 heap_print_object(ref); printf("\n"); );
222
223                                 /* keep the object alive until finalizer finishes */
224                                 MARK(ref);
225                                 break;
226
227 #if 0
228                         case FINAL_FINALIZING: /* object is still being finalized */
229                                 GC_LOG( printf("Finalizer not yet finished for: ");
230                                                 heap_print_object(ref); printf("\n"); );
231
232                                 /* keep the object alive until finalizer finishes */
233                                 MARK(ref);
234                                 break;
235 #endif
236
237                         default: /* case not yet covered */
238                                 vm_abort("mark_post: uncovered case (type=%d)", f_type);
239
240                         }
241                 }
242
243                 fe = list_next_unsynced(final_list, fe);
244         }
245 #endif /*defined(GCCONF_FINALIZER)*/
246
247         /* Clear all references in the rootset which have not yet been
248            marked. This applies to registered weak references. */
249
250         while (rs) {
251                 GC_LOG( dolog("GC: Clearing in rootset (%d entries) ...", rs->refcount); );
252
253                 /* mark all references of the rootset */
254                 for (i = 0; i < rs->refcount; i++) {
255
256                         /* load the reference */
257                         ref = *( rs->refs[i].ref );
258
259                         /* check for outside or null pointers */
260                         if (!POINTS_INTO(ref, start, end))
261                                 continue;
262
263                         /* is this a marking reference? */
264                         if (rs->refs[i].marks) {
265                                 assert(GC_IS_MARKED(ref));
266                         } else {
267
268                                 /* clear unmarked references */
269                                 if (!GC_IS_MARKED(ref)) {
270                                         GC_LOG( printf("Clearing Weak Reference %p at %p\n", ref, rs->refs[i]); );
271
272                                         *( rs->refs[i].ref ) = NULL;
273                                 }
274                         }
275                 }
276
277                 rs = rs->next;
278         }
279
280 }
281
282
283 /* mark_me *********************************************************************
284
285    Marks all Heap Objects which are reachable from a given root-set.
286
287    REMEMBER: Assumes all threads are stopped!
288
289    IN:
290           rs.....root set containing the references
291
292 *******************************************************************************/
293
294 void mark_me(rootset_t *rs)
295 {
296         rootset_t     *rstop;
297         java_object_t *ref;
298         void *start, *end;
299         int i;
300
301         /* TODO: this needs cleanup!!! */
302         start = heap_region_main->base;
303         end = heap_region_main->ptr;
304         rstop = rs;
305
306         GCSTAT_INIT(gcstat_mark_count);
307         GCSTAT_INIT(gcstat_mark_depth);
308         GCSTAT_INIT(gcstat_mark_depth_max);
309
310         while (rs) {
311                 GC_LOG( dolog("GC: Marking from rootset (%d entries) ...", rs->refcount); );
312
313                 /* mark all references of the rootset */
314                 for (i = 0; i < rs->refcount; i++) {
315
316                         /* is this a marking reference? */
317                         if (!rs->refs[i].marks)
318                                 continue;
319
320                         /* load the reference */
321                         ref = *( rs->refs[i].ref );
322
323                         /* check for outside or null pointers */
324                         if (!POINTS_INTO(ref, start, end))
325                                 continue;
326
327                         /* do the marking here */
328                         MARK(ref);
329
330                 }
331
332                 rs = rs->next;
333         }
334
335         GC_LOG( dolog("GC: Marking postprocessing ..."); );
336
337         /* perform some post processing of the marked heap */
338         mark_post(rstop);
339
340         GC_LOG( dolog("GC: Marking finished."); );
341
342 #if defined(ENABLE_STATISTICS)
343         GC_ASSERT(gcstat_mark_depth == 0);
344 #endif
345 }
346
347
348 /*
349  * These are local overrides for various environment variables in Emacs.
350  * Please do not remove this and leave it at the end of the file, where
351  * Emacs will automagically detect them.
352  * ---------------------------------------------------------------------
353  * Local variables:
354  * mode: c
355  * indent-tabs-mode: t
356  * c-basic-offset: 4
357  * tab-width: 4
358  * End:
359  * vim:noexpandtab:sw=4:ts=4:
360  */