* src/vmcore/linker.c (build_display): Removed superfluous recursion; return
[cacao.git] / src / mm / cacao-gc / rootset.c
1 /* mm/cacao-gc/rootset.c - GC module for root set management
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
33 #include "mm/memory.h"
34
35 #include "threads/threadlist.h"
36 #include "threads/thread.h"
37
38 #include "toolbox/logging.h"
39
40 #include "vm/global.h"
41 #include "vm/jit/replace.h"
42 #include "vm/jit/stacktrace.h"
43
44
45 rootset_t *rootset_create(void)
46 {
47         rootset_t *rs;
48
49         /* allocate memory for rootset */
50         rs = DNEW(rootset_t);
51
52         rs->next     = NULL;
53         rs->capacity = ROOTSET_INITIAL_CAPACITY;
54         rs->refcount = 0;
55
56         return rs;
57 }
58
59
60 rootset_t *rootset_resize(rootset_t *rs)
61 {
62         s4 size_old;
63         s4 size_new;
64
65         /* double the capacity of this rootset */
66         size_old = sizeof(rootset_t) + (rs->capacity - ROOTSET_INITIAL_CAPACITY) * sizeof(rootset_entry_t);
67         rs->capacity *= 2;
68         size_new = sizeof(rootset_t) + (rs->capacity - ROOTSET_INITIAL_CAPACITY) * sizeof(rootset_entry_t);
69
70         GC_LOG2( printf("Resizing rootset to capacity %d (%d -> %d)\n", rs->capacity, size_old, size_new); );
71
72         /* reallocate memory for rootset */
73         /* XXX DMREALLOC(ptr,type,num1,num2) */
74         rs = DMREALLOC(rs, u1, size_old, size_new);
75
76         return rs;
77 }
78
79
80 /* rootset_from_globals ********************************************************
81
82    Searches global variables to compile the global root set out of references
83    contained in them.
84
85    REMEMBER: All threads are stopped, so we don't have to lock the
86    lists in this function.
87
88    SEARCHES IN:
89      - thread objects (threads.c)
90      - classloader objects (loader.c)
91      - global reference table (jni.c)
92      - finalizer entries (final.c)
93
94 *******************************************************************************/
95
96 #define ROOTSET_ADD(adr,mrk,tp) \
97         if (refcount >= rs->capacity) \
98                 rs = rootset_resize(rs); \
99         rs->refs[refcount].ref     = (adr); \
100         rs->refs[refcount].marks   = (mrk); \
101         rs->refs[refcount].reftype = (tp); \
102         refcount++;
103
104 static rootset_t *rootset_from_globals(rootset_t *rs)
105 {
106         list_final_entry_t          *fe;
107         list_gcref_entry_t          *re;
108         int refcount;
109
110         GC_LOG( dolog("GC: Acquiring Root-Set from globals ..."); );
111
112         /* initialize the rootset struct */
113         GC_ASSERT(rs);
114         GC_ASSERT(rs->refcount == 0);
115         rs->thread = ROOTSET_DUMMY_THREAD;
116
117         refcount = rs->refcount;
118
119         /* walk through all registered strong references */
120         for (re = list_first(gc_reflist_strong); re != NULL; re = list_next(gc_reflist_strong, re)) {
121                 GC_LOG2( printf("Found Registered Reference: %p at %p of type %d\n", *(re->ref), re->ref, ref->reftype); );
122
123                 /* add this registered reference to the root set */
124                 ROOTSET_ADD(re->ref, true, re->reftype)
125         }
126
127         /* walk through all registered weak references */
128         for (re = list_first(gc_reflist_weak); re != NULL; re = list_next(gc_reflist_weak, re)) {
129                 GC_LOG2( printf("Found Registered Weak Reference: %p at %p of type %d\n", *(re->ref), re->ref, ref->reftype); );
130
131                 /* add this registered reference to the root set */
132                 ROOTSET_ADD(re->ref, false, re->reftype)
133         }
134
135         /* walk through all finalizer entries */
136         for (fe = list_first(final_list); fe != NULL; fe = list_next(final_list, fe)) {
137                 GC_LOG2( printf("Found Finalizer Entry: %p\n", (void *) fe->o); );
138
139                 /* add this object with finalizer to the root set */
140                 ROOTSET_ADD(&( fe->o ), false, GC_REFTYPE_FINALIZER)
141         }
142
143         /* remeber how many references there are inside this root set */
144         rs->refcount = refcount;
145
146         return rs;
147 }
148
149
150 static rootset_t *rootset_from_classes(rootset_t *rs)
151 {
152         classinfo         *c;
153         fieldinfo         *f;
154         void *sys_start, *sys_end;
155         int refcount;
156         int i;
157
158         GC_LOG( dolog("GC: Acquiring Root-Set from classes ..."); );
159
160         /* TODO: cleanup!!! */
161         sys_start = heap_region_sys->base;
162         sys_end = heap_region_sys->ptr;
163
164         refcount = rs->refcount;
165
166         /* walk through all classinfo blocks */
167         c = sys_start;
168         while (c < (classinfo *) sys_end) {
169
170                 GC_LOG2( printf("Searching in class "); class_print(c); printf("\n"); );
171
172                 /* walk through all fields */
173                 f = c->fields;
174                 for (i = 0; i < c->fieldscount; i++, f++) {
175
176                         /* check if this is a static reference */
177                         if (!IS_ADR_TYPE(f->type) || !(f->flags & ACC_STATIC))
178                                 continue;
179
180                         /* check for outside or null pointers */
181                         if (f->value->a == NULL)
182                                 continue;
183
184                         GC_LOG2( printf("Found Static Field Reference: %p\n", (void *) f->value->a);
185                                         printf("\tfrom field: "); field_print(f); printf("\n");
186                                         printf("\tto object : "); heap_print_object(f->value->a); printf("\n"); );
187
188                         /* add this static field reference to the root set */
189                         ROOTSET_ADD(f->value, true, GC_REFTYPE_CLASSREF);
190
191                 }
192
193                 /* skip to next classinfo block */
194                 c++;
195                 c = (classinfo *) (GC_ALIGN((ptrint) c, GC_ALIGN_SIZE));
196
197         }
198
199         /* remeber how many references there are inside this root set */
200         rs->refcount = refcount;
201
202         return rs;
203 }
204
205
206 /* rootset_from_thread *********************************************************
207
208    Searches the stack of the passed thread for references and compiles a
209    root set out of them.
210
211    NOTE: uses dump memory!
212
213    IN:
214           thread...TODO
215       rs.......TODO
216
217    OUT:
218           TODO!!!
219
220 *******************************************************************************/
221
222 static rootset_t *rootset_from_thread(threadobject *thread, rootset_t *rs)
223 {
224         executionstate_t *es;
225         sourcestate_t    *ss;
226         sourceframe_t    *sf;
227         localref_table   *lrt;
228         int refcount;
229         int i;
230
231 #if defined(ENABLE_THREADS)
232         GC_ASSERT(thread != NULL);
233         GC_LOG( dolog("GC: Acquiring Root-Set from thread (tid=%p) ...", (void *) thread->tid); );
234 #else
235         GC_ASSERT(thread == NULL);
236         GC_LOG( dolog("GC: Acquiring Root-Set from single-thread ..."); );
237 #endif
238
239         GC_LOG2( printf("Stacktrace of thread:\n");
240                         threads_thread_print_stacktrace(thread); );
241
242         /* get the sourcestate of the threads */
243         es = GC_EXECUTIONSTATE;
244         ss = GC_SOURCESTATE;
245
246         GC_ASSERT(es);
247         GC_ASSERT(ss);
248
249         /* print our full source state */
250         GC_LOG2( replace_sourcestate_println(ss); );
251
252         /* initialize the rootset struct */
253         GC_ASSERT(rs);
254         GC_ASSERT(rs->refcount == 0);
255         rs->thread = thread;
256
257         refcount = rs->refcount;
258
259         /* now inspect the source state to compile the root set */
260         for (sf = ss->frames; sf != NULL; sf = sf->down) {
261
262                 GC_LOG( printf("Source Frame: localcount=%d, stackdepth=%d, syncslots=%d\n", sf->javalocalcount, sf->javastackdepth, sf->syncslotcount); );
263
264                 for (i = 0; i < sf->javalocalcount; i++) {
265
266                         /* we only need to consider references */
267                         if (sf->javalocaltype[i] != TYPE_ADR)
268                                 continue;
269
270                         GC_LOG2( printf("Found Reference (Java Local): %p\n", (void *) sf->javalocals[i].a); );
271
272                         /* add this reference to the root set */
273                         ROOTSET_ADD((java_object_t **) &( sf->javalocals[i] ), true, GC_REFTYPE_STACK);
274
275                 }
276
277                 for (i = 0; i < sf->javastackdepth; i++) {
278
279                         /* we only need to consider references */
280                         if (sf->javastacktype[i] != TYPE_ADR)
281                                 continue;
282
283                         GC_LOG2( printf("Found Reference (Java Stack): %p\n", (void *) sf->javastack[i].a); );
284
285                         /* add this reference to the root set */
286                         ROOTSET_ADD((java_object_t **) &( sf->javastack[i] ), true, GC_REFTYPE_STACK);
287
288                 }
289
290                 for (i = 0; i < sf->syncslotcount; i++) {
291
292                         GC_LOG( printf("Found Reference (Sync Slot): %p\n", (void *) sf->syncslots[i].a); );
293
294                         /* add this reference to the root set */
295                         ROOTSET_ADD((java_object_t **) &( sf->syncslots[i] ), true, GC_REFTYPE_STACK);
296
297                 }
298         }
299
300         /* now walk through all local references of this thread */
301 #if defined(ENABLE_THREADS)
302         lrt = thread->_localref_table;
303 #else
304         lrt = LOCALREFTABLE;
305 #endif
306         while (lrt) {
307
308                 for (i = 0; i < lrt->used; i++) {
309
310                         /* there should be no null pointers in here */
311                         GC_ASSERT(lrt->refs[i] != NULL);
312
313                         GC_LOG2( printf("Found LocalRef: %p\n", (void *) lrt->refs[i]); );
314
315                         /* add this reference to the root set */
316                         ROOTSET_ADD(&( lrt->refs[i] ), true, GC_REFTYPE_LOCALREF);
317
318                 }
319
320                 lrt = lrt->prev;
321         }
322
323         /* remeber how many references there are inside this root set */
324         rs->refcount = refcount;
325
326         return rs;
327 }
328
329
330 rootset_t *rootset_readout()
331 {
332         rootset_t    *rs_top;
333         rootset_t    *rs;
334         threadobject *t;
335
336         /* find the global rootset ... */
337         rs_top = rootset_create();
338         rs_top = rootset_from_globals(rs_top);
339         rs_top = rootset_from_classes(rs_top);
340
341         /* ... and the rootsets for the threads */
342         rs = rs_top;
343 #if defined(ENABLE_THREADS)
344         for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
345
346                 /* ignore threads which are in state NEW */
347                 if (t->state == THREAD_STATE_NEW)
348                         continue;
349
350                 rs->next = rootset_create();
351                 rs->next = rootset_from_thread(t, rs->next);
352
353                 rs = rs->next;
354         }
355 #else
356         t = THREADOBJECT;
357
358         rs->next = rootset_create();
359         rs->next = rootset_from_thread(t, rs->next);
360 #endif
361
362         return rs_top;
363 }
364
365
366 void rootset_writeback(rootset_t *rs)
367 {
368         threadobject     *thread;
369
370         /* walk through all rootsets */
371         while (rs) {
372                 thread = rs->thread;
373
374                 /* does this rootset belong to a thread? */
375                 if (thread != ROOTSET_DUMMY_THREAD) {
376 #if defined(ENABLE_THREADS)
377                         GC_ASSERT(thread != NULL);
378                         GC_LOG( dolog("GC: Writing back Root-Set to thread (tid=%p) ...", (void *) thread->tid); );
379 #else
380                         GC_ASSERT(thread == NULL);
381                         GC_LOG( dolog("GC: Writing back Root-Set to single-thread ..."); );
382 #endif
383
384                         /* now rebuild the stack of the thread */
385                         replace_gc_into_native(thread);
386                 }
387
388                 rs = rs->next;
389         }
390
391 }
392
393
394 /* Debugging ******************************************************************/
395
396 #if !defined(NDEBUG)
397 static const char* reftype_names[] = {
398                 "THREADOBJECT", "CLASSLOADER ", "GLOBAL-REF  ",
399                 "FINALIZER   ", "LOCAL-REF   ", "ON-STACK-ADR",
400                 "STATIC FIELD", "LOCKRECORD  "
401 };
402
403 void rootset_print(rootset_t *rs)
404 {
405         java_object_t *o;
406         int i;
407
408         /* walk through all rootsets in the chain */
409         printf("Root Set Chain:\n");
410         while (rs) {
411
412                 /* print the thread this rootset belongs to */
413                 if (rs->thread == ROOTSET_DUMMY_THREAD) {
414                         printf("\tGlobal Root Set:\n");
415                 } else {
416 #if defined(ENABLE_THREADS)
417                         printf("\tLocal Root Set with Thread-Id %p:\n", (void *) rs->thread->tid);
418 #else
419                         printf("\tLocal Root Set:\n");
420 #endif
421                 }
422
423                 /* print the references in this rootset */
424                 printf("\tReferences (%d / %d):\n", rs->refcount, rs->capacity);
425                 for (i = 0; i < rs->refcount; i++) {
426
427                         o = *( rs->refs[i].ref );
428
429                         /*printf("\t\tReference at %p points to ...\n", (void *) rs->refs[i]);*/
430                         printf("\t\t");
431                         printf("%s ", reftype_names[rs->refs[i].reftype]);
432                         if (rs->refs[i].marks)
433                                 printf("STRONG");
434                         else
435                                 printf("  WEAK");
436                         printf(" ");
437                         heap_print_object(o);
438                         printf("\n");
439
440                 }
441
442                 rs = rs->next;
443
444         }
445
446 }
447 #endif
448
449
450 /*
451  * These are local overrides for various environment variables in Emacs.
452  * Please do not remove this and leave it at the end of the file, where
453  * Emacs will automagically detect them.
454  * ---------------------------------------------------------------------
455  * Local variables:
456  * mode: c
457  * indent-tabs-mode: t
458  * c-basic-offset: 4
459  * tab-width: 4
460  * End:
461  * vim:noexpandtab:sw=4:ts=4:
462  */