1 /* mm/cacao-gc/rootset.c - GC module for root set management
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
8 This file is part of CACAO.
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.
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.
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
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"
42 rootset_t *rootset_create(void)
46 /* allocate memory for rootset */
50 rs->capacity = ROOTSET_INITIAL_CAPACITY;
57 rootset_t *rootset_resize(rootset_t *rs)
62 /* double the capacity of this rootset */
63 size_old = sizeof(rootset_t) + (rs->capacity - ROOTSET_INITIAL_CAPACITY) * sizeof(rootset_entry_t);
65 size_new = sizeof(rootset_t) + (rs->capacity - ROOTSET_INITIAL_CAPACITY) * sizeof(rootset_entry_t);
67 GC_LOG2( printf("Resizing rootset to capacity %d (%d -> %d)\n", rs->capacity, size_old, size_new); );
69 /* reallocate memory for rootset */
70 /* XXX DMREALLOC(ptr,type,num1,num2) */
71 rs = DMREALLOC(rs, u1, size_old, size_new);
77 /* rootset_from_globals ********************************************************
79 Searches global variables to compile the global root set out of references
82 REMEMBER: All threads are stopped, so we can use unsynced access
86 - thread objects (threads.c)
87 - classloader objects (loader.c)
88 - global reference table (jni.c)
89 - finalizer entries (final.c)
91 *******************************************************************************/
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); \
101 static rootset_t *rootset_from_globals(rootset_t *rs)
103 list_final_entry_t *fe;
104 list_gcref_entry_t *re;
107 GC_LOG( dolog("GC: Acquiring Root-Set from globals ..."); );
109 /* initialize the rootset struct */
111 GC_ASSERT(rs->refcount == 0);
112 rs->thread = ROOTSET_DUMMY_THREAD;
114 refcount = rs->refcount;
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); );
120 /* add this registered reference to the root set */
121 ROOTSET_ADD(re->ref, true, re->reftype)
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); );
128 /* add this registered reference to the root set */
129 ROOTSET_ADD(re->ref, false, re->reftype)
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); );
136 /* add this object with finalizer to the root set */
137 ROOTSET_ADD(&( fe->o ), false, GC_REFTYPE_FINALIZER)
140 /* remeber how many references there are inside this root set */
141 rs->refcount = refcount;
147 static rootset_t *rootset_from_classes(rootset_t *rs)
151 void *sys_start, *sys_end;
155 GC_LOG( dolog("GC: Acquiring Root-Set from classes ..."); );
157 /* TODO: cleanup!!! */
158 sys_start = heap_region_sys->base;
159 sys_end = heap_region_sys->ptr;
161 refcount = rs->refcount;
163 /* walk through all classinfo blocks */
165 while (c < (classinfo *) sys_end) {
167 GC_LOG2( printf("Searching in class "); class_print(c); printf("\n"); );
169 /* walk through all fields */
171 for (i = 0; i < c->fieldscount; i++, f++) {
173 /* check if this is a static reference */
174 if (!IS_ADR_TYPE(f->type) || !(f->flags & ACC_STATIC))
177 /* check for outside or null pointers */
178 if (f->value->a == NULL)
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"); );
185 /* add this static field reference to the root set */
186 ROOTSET_ADD(f->value, true, GC_REFTYPE_CLASSREF);
190 /* skip to next classinfo block */
192 c = (classinfo *) (GC_ALIGN((ptrint) c, GC_ALIGN_SIZE));
196 /* remeber how many references there are inside this root set */
197 rs->refcount = refcount;
203 /* rootset_from_thread *********************************************************
205 Searches the stack of the passed thread for references and compiles a
206 root set out of them.
208 NOTE: uses dump memory!
217 *******************************************************************************/
219 static rootset_t *rootset_from_thread(threadobject *thread, rootset_t *rs)
221 executionstate_t *es;
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); );
232 GC_ASSERT(thread == NULL);
233 GC_LOG( dolog("GC: Acquiring Root-Set from single-thread ..."); );
236 GC_LOG2( printf("Stacktrace of thread:\n");
237 threads_thread_print_stacktrace(thread); );
239 /* get the sourcestate of the threads */
240 es = GC_EXECUTIONSTATE;
246 /* print our full source state */
247 GC_LOG2( replace_sourcestate_println(ss); );
249 /* initialize the rootset struct */
251 GC_ASSERT(rs->refcount == 0);
254 refcount = rs->refcount;
256 /* now inspect the source state to compile the root set */
257 for (sf = ss->frames; sf != NULL; sf = sf->down) {
259 GC_LOG( printf("Source Frame: localcount=%d, stackdepth=%d, syncslots=%d\n", sf->javalocalcount, sf->javastackdepth, sf->syncslotcount); );
261 for (i = 0; i < sf->javalocalcount; i++) {
263 /* we only need to consider references */
264 if (sf->javalocaltype[i] != TYPE_ADR)
267 GC_LOG2( printf("Found Reference (Java Local): %p\n", (void *) sf->javalocals[i].a); );
269 /* add this reference to the root set */
270 ROOTSET_ADD((java_object_t **) &( sf->javalocals[i] ), true, GC_REFTYPE_STACK);
274 for (i = 0; i < sf->javastackdepth; i++) {
276 /* we only need to consider references */
277 if (sf->javastacktype[i] != TYPE_ADR)
280 GC_LOG2( printf("Found Reference (Java Stack): %p\n", (void *) sf->javastack[i].a); );
282 /* add this reference to the root set */
283 ROOTSET_ADD((java_object_t **) &( sf->javastack[i] ), true, GC_REFTYPE_STACK);
287 for (i = 0; i < sf->syncslotcount; i++) {
289 GC_LOG( printf("Found Reference (Sync Slot): %p\n", (void *) sf->syncslots[i].a); );
291 /* add this reference to the root set */
292 ROOTSET_ADD((java_object_t **) &( sf->syncslots[i] ), true, GC_REFTYPE_STACK);
297 /* now walk through all local references of this thread */
298 #if defined(ENABLE_THREADS)
299 lrt = thread->_localref_table;
305 for (i = 0; i < lrt->used; i++) {
307 /* there should be no null pointers in here */
308 GC_ASSERT(lrt->refs[i] != NULL);
310 GC_LOG2( printf("Found LocalRef: %p\n", (void *) lrt->refs[i]); );
312 /* add this reference to the root set */
313 ROOTSET_ADD(&( lrt->refs[i] ), true, GC_REFTYPE_LOCALREF);
320 /* remeber how many references there are inside this root set */
321 rs->refcount = refcount;
327 rootset_t *rootset_readout()
331 threadobject *thread;
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);
338 /* ... and the rootsets for the threads */
340 #if defined(ENABLE_THREADS)
341 for (thread = threads_list_first(); thread != NULL; thread = threads_list_next(thread)) {
343 /* ignore threads which are in state NEW */
344 if (thread->state == THREAD_STATE_NEW)
347 rs->next = rootset_create();
348 rs->next = rootset_from_thread(thread, rs->next);
353 thread = THREADOBJECT;
355 rs->next = rootset_create();
356 rs->next = rootset_from_thread(thread, rs->next);
363 void rootset_writeback(rootset_t *rs)
365 threadobject *thread;
367 /* walk through all rootsets */
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); );
377 GC_ASSERT(thread == NULL);
378 GC_LOG( dolog("GC: Writing back Root-Set to single-thread ..."); );
381 /* now rebuild the stack of the thread */
382 replace_gc_into_native(thread);
391 /* Debugging ******************************************************************/
394 static const char* reftype_names[] = {
395 "THREADOBJECT", "CLASSLOADER ", "GLOBAL-REF ",
396 "FINALIZER ", "LOCAL-REF ", "ON-STACK-ADR",
397 "STATIC FIELD", "LOCKRECORD "
400 void rootset_print(rootset_t *rs)
405 /* walk through all rootsets in the chain */
406 printf("Root Set Chain:\n");
409 /* print the thread this rootset belongs to */
410 if (rs->thread == ROOTSET_DUMMY_THREAD) {
411 printf("\tGlobal Root Set:\n");
413 #if defined(ENABLE_THREADS)
414 printf("\tLocal Root Set with Thread-Id %p:\n", (void *) rs->thread->tid);
416 printf("\tLocal Root Set:\n");
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++) {
424 o = *( rs->refs[i].ref );
426 /*printf("\t\tReference at %p points to ...\n", (void *) rs->refs[i]);*/
428 printf("%s ", reftype_names[rs->refs[i].reftype]);
429 if (rs->refs[i].marks)
434 heap_print_object(o);
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 * ---------------------------------------------------------------------
454 * indent-tabs-mode: t
458 * vim:noexpandtab:sw=4:ts=4: