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