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
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"
44 rootset_t *rootset_create(void)
57 /* rootset_from_globals ********************************************************
59 Searches global variables to compile the global root set out of references
63 - thread objects (threads.c)
64 - classloader objects (loader.c)
65 - global reference table (jni.c)
66 - finalizer entries (final.c)
68 *******************************************************************************/
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); \
77 void rootset_from_globals(rootset_t *rs)
79 list_final_entry_t *fe;
80 list_gcref_entry_t *re;
83 GC_LOG( dolog("GC: Acquiring Root-Set from globals ..."); );
85 /* initialize the rootset struct */
87 GC_ASSERT(rs->refcount == 0);
88 rs->thread = ROOTSET_DUMMY_THREAD;
92 refcount = rs->refcount;
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);
99 GC_LOG2( printf("Found Registered Reference: %p at %p\n", *(re->ref), re->ref); );
101 /* add this registered reference to the root set */
102 ROOTSET_ADD(re->ref, true, REFTYPE_REGISTERED)
104 re = list_next_unsynced(gc_reflist, re);
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);
112 GC_LOG2( printf("Found Finalizer Entry: %p\n", (void *) fe->o); );
114 /* add this object with finalizer to the root set */
115 ROOTSET_ADD(&( fe->o ), false, REFTYPE_FINALIZER)
117 fe = list_next_unsynced(final_list, fe);
120 /* remeber how many references there are inside this root set */
121 rs->refcount = refcount;
126 void rootset_from_classes(rootset_t *rs)
130 void *sys_start, *sys_end;
134 GC_LOG( dolog("GC: Acquiring Root-Set from classes ..."); );
136 /* TODO: cleanup!!! */
137 sys_start = heap_region_sys->base;
138 sys_end = heap_region_sys->ptr;
140 refcount = rs->refcount;
142 /* walk through all classinfo blocks */
144 while (c < (classinfo *) sys_end) {
146 GC_LOG2( printf("Searching in class "); class_print(c); printf("\n"); );
148 /* walk through all fields */
150 for (i = 0; i < c->fieldscount; i++, f++) {
152 /* check if this is a static reference */
153 if (!IS_ADR_TYPE(f->type) || !(f->flags & ACC_STATIC))
156 /* check for outside or null pointers */
157 if (f->value.a == NULL)
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"); );
164 /* add this static field reference to the root set */
165 ROOTSET_ADD(&( f->value.a ), true, REFTYPE_CLASSREF);
169 /* skip to next classinfo block */
171 c = (classinfo *) (GC_ALIGN((ptrint) c, GC_ALIGN_SIZE));
175 /* remeber how many references there are inside this root set */
176 rs->refcount = refcount;
181 /* rootset_from_thread *********************************************************
183 Searches the stack of the passed thread for references and compiles a
184 root set out of them.
186 NOTE: uses dump memory!
195 *******************************************************************************/
197 void rootset_from_thread(threadobject *thread, rootset_t *rs)
199 executionstate_t *es;
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); );
210 GC_ASSERT(thread == NULL);
211 GC_LOG( dolog("GC: Acquiring Root-Set from single-thread ..."); );
214 GC_LOG2( printf("Stacktrace of thread:\n");
215 threads_thread_print_stacktrace(thread); );
217 /* get the sourcestate of the threads */
218 es = GC_EXECUTIONSTATE;
224 /* print our full source state */
225 GC_LOG2( replace_sourcestate_println(ss); );
227 /* initialize the rootset struct */
229 GC_ASSERT(rs->refcount == 0);
234 refcount = rs->refcount;
236 /* now inspect the source state to compile the root set */
237 for (sf = ss->frames; sf != NULL; sf = sf->down) {
239 GC_LOG( printf("Source Frame: localcount=%d, stackdepth=%d, syncslots=%d\n", sf->javalocalcount, sf->javastackdepth, sf->syncslotcount); );
241 for (i = 0; i < sf->javalocalcount; i++) {
243 /* we only need to consider references */
244 if (sf->javalocaltype[i] != TYPE_ADR)
247 GC_LOG2( printf("Found Reference (Java Local): %p\n", (void *) sf->javalocals[i].a); );
249 /* add this reference to the root set */
250 ROOTSET_ADD((java_objectheader **) &( sf->javalocals[i] ), true, REFTYPE_STACK);
254 for (i = 0; i < sf->javastackdepth; i++) {
256 /* we only need to consider references */
257 if (sf->javastacktype[i] != TYPE_ADR)
260 GC_LOG2( printf("Found Reference (Java Stack): %p\n", (void *) sf->javastack[i].a); );
262 /* add this reference to the root set */
263 ROOTSET_ADD((java_objectheader **) &( sf->javastack[i] ), true, REFTYPE_STACK);
267 for (i = 0; i < sf->syncslotcount; i++) {
269 GC_LOG( printf("Found Reference (Sync Slot): %p\n", (void *) sf->syncslots[i].a); );
271 /* add this reference to the root set */
272 ROOTSET_ADD((java_objectheader **) &( sf->syncslots[i] ), true, REFTYPE_STACK);
277 /* now walk through all local references of this thread */
278 #if defined(ENABLE_THREADS)
279 lrt = thread->_localref_table;
285 for (i = 0; i < lrt->used; i++) {
287 /* there should be no null pointers in here */
288 GC_ASSERT(lrt->refs[i] != NULL);
290 GC_LOG( printf("Found LocalRef: %p\n", (void *) lrt->refs[i]); );
292 /* add this reference to the root set */
293 ROOTSET_ADD(&( lrt->refs[i] ), true, REFTYPE_LOCALREF);
300 /* remeber how many references there are inside this root set */
301 rs->refcount = refcount;
306 rootset_t *rootset_readout()
310 threadobject *thread;
312 /* find the global rootset ... */
313 rs_top = rootset_create();
314 rootset_from_globals(rs_top);
315 rootset_from_classes(rs_top);
317 /* ... and the rootsets for the threads */
319 #if defined(ENABLE_THREADS)
320 for (thread = threads_list_first(); thread != NULL; thread = threads_list_next(thread)) {
321 rs->next = rootset_create();
324 rootset_from_thread(thread, rs);
327 thread = THREADOBJECT;
329 rs->next = rootset_create();
332 rootset_from_thread(thread, rs);
339 void rootset_writeback(rootset_t *rs)
341 threadobject *thread;
343 executionstate_t *es;
345 /* walk through all rootsets */
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); );
355 GC_ASSERT(thread == NULL);
356 GC_LOG( dolog("GC: Writing back Root-Set to single-thread ..."); );
359 /* now write back the modified sourcestate */
362 replace_build_execution_state_intern(ss, es);
371 /* Debugging ******************************************************************/
374 const char* ref_type_names[] = {
375 "XXXXXX", "REGIST", "CLASSL",
376 "GLOBAL", "FINAL ", "LOCAL ",
380 void rootset_print(rootset_t *rs)
382 java_objectheader *o;
385 /* walk through all rootsets in the chain */
386 printf("Root Set Chain:\n");
389 /* print the thread this rootset belongs to */
390 if (rs->thread == ROOTSET_DUMMY_THREAD) {
391 printf("\tGlobal Root Set:\n");
393 #if defined(ENABLE_THREADS)
394 printf("\tLocal Root Set with Thread-Id %p:\n", (void *) rs->thread->tid);
396 printf("\tLocal Root Set:\n");
400 /* print the references in this rootset */
401 printf("\tReferences (%d):\n", rs->refcount);
402 for (i = 0; i < rs->refcount; i++) {
404 o = *( rs->refs[i] );
406 /*printf("\t\tReference at %p points to ...\n", (void *) rs->refs[i]);*/
408 printf("%s ", ref_type_names[rs->ref_type[i]]);
409 if (rs->ref_marks[i])
410 printf("MARK+UPDATE");
414 heap_print_object(o);
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 * ---------------------------------------------------------------------
434 * indent-tabs-mode: t
438 * vim:noexpandtab:sw=4:ts=4: