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