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