1 /* src/mm/cacao-gc/gc.c - main garbage collector methods
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 "threads/lock-common.h"
35 #include "threads/threads-common.h"
45 #include "mm/memory.h"
46 #include "toolbox/logging.h"
47 #include "vm/finalizer.h"
49 #include "vmcore/rt-timing.h"
52 /* Global Variables ***********************************************************/
56 bool gc_notify_finalizer;
60 #if defined(ENABLE_THREADS)
61 java_objectheader *gc_global_lock;
64 #if !defined(ENABLE_THREADS)
65 executionstate_t *_no_threads_executionstate;
66 sourcestate_t *_no_threads_sourcestate;
70 /* gc_init *********************************************************************
72 Initializes the garbage collector.
74 *******************************************************************************/
76 #define GC_SYS_SIZE (20*1024*1024)
78 void gc_init(u4 heapmaxsize, u4 heapstartsize)
81 dolog("GC: Initialising with heap-size %d (max. %d)",
82 heapstartsize, heapmaxsize);
87 /* set global variables */
91 /* create list for external references */
92 gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
94 #if defined(ENABLE_THREADS)
95 /* create global gc lock object */
96 gc_global_lock = NEW(java_objectheader);
97 lock_init_object_lock(gc_global_lock);
100 /* region for uncollectable objects */
101 heap_region_sys = NEW(regioninfo_t);
102 if (!region_create(heap_region_sys, GC_SYS_SIZE))
103 vm_abort("gc_init: region_create failed: out of memory");
105 /* region for java objects */
106 heap_region_main = NEW(regioninfo_t);
107 if (!region_create(heap_region_main, heapstartsize))
108 vm_abort("gc_init: region_create failed: out of memory");
110 heap_current_size = heapstartsize;
111 heap_maximal_size = heapmaxsize;
115 /* gc_reference_register *******************************************************
117 Register an external reference which points onto the Heap and keeps
118 objects alive (strong reference).
120 *******************************************************************************/
122 void gc_reference_register(java_objectheader **ref)
124 list_gcref_entry_t *re;
126 /* the reference needs to be registered before it is set, so make sure the
127 reference is not yet set */
128 GC_ASSERT(*ref == NULL);
130 /* are we called from threads_preinit? */
131 if (gc_reflist == NULL) {
132 GC_LOG( dolog("GC: Unable to register Reference!"); );
136 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
138 re = NEW(list_gcref_entry_t);
142 list_add_last(gc_reflist, re);
146 /* gc_collect ******************************************************************
148 This is the main machinery which manages a collection. It should be run by
149 the thread which triggered the collection.
154 STEPS OF A COLLECTION:
157 *******************************************************************************/
159 void gc_collect(s4 level)
165 stacktracebuffer *stb;
167 #if defined(ENABLE_RT_TIMING)
168 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
171 /* enter the global gc lock */
172 LOCK_MONITOR_ENTER(gc_global_lock);
174 /* remember start of dump memory area */
175 dumpsize = dump_size();
177 GCSTAT_COUNT(gcstat_collections);
179 RT_TIMING_GET_TIME(time_start);
181 /* let everyone know we want to do a collection */
182 GC_ASSERT(!gc_pending);
185 /* finalizer is not notified, unless marking tells us to do so */
186 gc_notify_finalizer = false;
188 #if defined(ENABLE_THREADS)
189 /* stop the world here */
190 GC_LOG( dolog("GC: Suspending threads ..."); );
191 GC_LOG( threads_dump(); );
193 /*GC_LOG( threads_dump(); );*/
194 GC_LOG( dolog("GC: Suspension finished."); );
198 /* get the stacktrace of the current thread and make sure it is non-empty */
199 GC_LOG( printf("Stacktrace of current thread:\n"); );
200 sfi = STACKFRAMEINFO;
201 stb = stacktrace_create(sfi);
203 vm_abort("gc_collect: no stacktrace available for current thread!");
204 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
207 /* sourcestate of the current thread, assuming we are in the native world */
208 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
209 #if defined(ENABLE_THREADS)
210 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
212 replace_gc_from_native(THREADOBJECT, NULL, NULL);
214 /* everyone is halted now, we consider ourselves running */
215 GC_ASSERT(!gc_running);
219 RT_TIMING_GET_TIME(time_suspend);
221 GC_LOG( heap_println_usage(); );
222 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
224 /* find the global and local rootsets */
225 rs = rootset_readout();
226 GC_LOG( rootset_print(rs); );
228 RT_TIMING_GET_TIME(time_rootset);
232 /* mark the objects considering the given rootset */
234 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
236 RT_TIMING_GET_TIME(time_mark);
238 /* compact the heap */
239 compact_me(rs, heap_region_main);
240 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
242 #if defined(ENABLE_MEMCHECK)
243 /* invalidate the rest of the main region */
244 region_invalidate(heap_region_main);
247 RT_TIMING_GET_TIME(time_compact);
249 /* check if we should increase the heap size */
250 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
251 heap_increase_size(rs);
255 /* copy the heap to new region */
257 regioninfo_t *src, *dst;
259 src = heap_region_main;
260 dst = NEW(regioninfo_t);
261 region_create(dst, heap_current_size);
262 copy_me(heap_region_main, dst, rs);
263 heap_region_main = dst;
265 /* invalidate old heap */
266 memset(src->base, 0x66, src->size);
270 /* TODO: check my return value! */
271 /*heap_increase_size();*/
273 /* write back the rootset to update root references */
274 GC_LOG( rootset_print(rs); );
275 rootset_writeback(rs);
277 #if defined(ENABLE_STATISTICS)
282 /* we are no longer running */
285 #if defined(ENABLE_THREADS)
286 /* start the world again */
287 GC_LOG( dolog("GC: Reanimating world ..."); );
288 threads_startworld();
289 /*GC_LOG( threads_dump(); );*/
292 #if defined(GCCONF_FINALIZER)
293 /* does the finalizer need to be notified */
294 if (gc_notify_finalizer)
298 RT_TIMING_GET_TIME(time_end);
300 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
301 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
302 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
303 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
304 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
305 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
307 /* free dump memory area */
308 dump_release(dumpsize);
310 /* leave the global gc lock */
311 LOCK_MONITOR_EXIT(gc_global_lock);
316 #if defined(ENABLE_THREADS)
317 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
321 /* check if the thread suspended itself */
323 GC_LOG( dolog("GC: Suspended myself!"); );
327 /* thread was forcefully suspended */
328 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
330 /* check where this thread came to a halt */
331 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
333 if (thread->gc_critical) {
334 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
338 /* wait till this thread suspends itself */
342 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
344 /* we assume we are in a native! */
345 replace_gc_from_native(thread, pc, sp);
353 code = code_find_codeinfo_for_pc_nocheck(pc);
356 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
359 /* arm the replacement points of the code this thread is in */
360 replace_activate_replacement_points(code, false);
362 /* wait till this thread suspends itself */
366 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
368 /* re-suspend me later */
369 /* TODO: implement me! */
370 /* TODO: (this is a rare race condition which was not yet triggered) */
378 /* this point should never be reached */
385 /* gc_call *********************************************************************
387 Forces a full collection of the whole Java Heap.
388 This is the function which is called by java.lang.Runtime.gc()
390 *******************************************************************************/
395 dolog("GC: Forced Collection ...");
397 GCSTAT_COUNT(gcstat_collections_forced);
402 dolog("GC: Forced Collection finished.");
406 /* gc_invoke_finalizers ********************************************************
408 Forces invocation of all the finalizers for objects which are reclaimable.
409 This is the function which is called by the finalizer thread.
411 *******************************************************************************/
413 void gc_invoke_finalizers(void)
416 dolog("GC: Invoking finalizers ...");
421 dolog("GC: Invoking finalizers finished.");
425 /* gc_finalize_all *************************************************************
427 Forces the finalization of all objects on the Java Heap.
428 This is the function which is called by java.lang.Runtime.exit()
430 We do this by setting all objects with finalizers to reclaimable,
431 which is inherently dangerouse because objects may still be alive.
433 *******************************************************************************/
435 void gc_finalize_all(void)
438 /* doing this is deprecated, inform the user */
439 dolog("gc_finalize_all: Deprecated!");
442 /* set all objects with finalizers to reclaimable */
443 final_set_all_reclaimable();
445 /* notify the finalizer thread */
450 /* Informational getter functions *********************************************/
452 s8 gc_get_heap_size(void) { return heap_current_size; }
453 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
454 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
455 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
458 /* Statistics *****************************************************************/
460 #if defined(ENABLE_STATISTICS)
461 int gcstat_collections;
462 int gcstat_collections_forced;
463 int gcstat_mark_depth;
464 int gcstat_mark_depth_max;
465 int gcstat_mark_count;
467 void gcstat_println()
469 printf("\nGCSTAT - General Statistics:\n");
470 printf("\t# of collections: %d\n", gcstat_collections);
471 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
473 printf("\nGCSTAT - Marking Statistics:\n");
474 printf("\t# of objects marked: %d\n", gcstat_mark_count);
475 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
477 printf("\nGCSTAT - Compaction Statistics:\n");
481 #endif /* defined(ENABLE_STATISTICS) */
485 * These are local overrides for various environment variables in Emacs.
486 * Please do not remove this and leave it at the end of the file, where
487 * Emacs will automagically detect them.
488 * ---------------------------------------------------------------------
491 * indent-tabs-mode: t
495 * vim:noexpandtab:sw=4:ts=4: