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 #if defined(ENABLE_THREADS)
131 /* XXX dirty hack because threads_init() not yet called */
132 if (THREADOBJECT == NULL) {
133 GC_LOG( dolog("GC: Unable to register Reference!"); );
138 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
140 re = NEW(list_gcref_entry_t);
144 list_add_last(gc_reflist, re);
148 void gc_reference_unregister(java_objectheader **ref)
150 vm_abort("gc_reference_unregister: IMPLEMENT ME!");
154 /* gc_collect ******************************************************************
156 This is the main machinery which manages a collection. It should be run by
157 the thread which triggered the collection.
162 STEPS OF A COLLECTION:
165 *******************************************************************************/
167 void gc_collect(s4 level)
173 stacktracebuffer *stb;
175 #if defined(ENABLE_RT_TIMING)
176 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
179 /* enter the global gc lock */
180 LOCK_MONITOR_ENTER(gc_global_lock);
182 /* remember start of dump memory area */
183 dumpsize = dump_size();
185 GCSTAT_COUNT(gcstat_collections);
187 RT_TIMING_GET_TIME(time_start);
189 /* let everyone know we want to do a collection */
190 GC_ASSERT(!gc_pending);
193 /* finalizer is not notified, unless marking tells us to do so */
194 gc_notify_finalizer = false;
196 #if defined(ENABLE_THREADS)
197 /* stop the world here */
198 GC_LOG( dolog("GC: Suspending threads ..."); );
199 GC_LOG( threads_dump(); );
201 /*GC_LOG( threads_dump(); );*/
202 GC_LOG( dolog("GC: Suspension finished."); );
206 /* get the stacktrace of the current thread and make sure it is non-empty */
207 GC_LOG( printf("Stacktrace of current thread:\n"); );
208 sfi = STACKFRAMEINFO;
209 stb = stacktrace_create(sfi);
211 vm_abort("gc_collect: no stacktrace available for current thread!");
212 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
215 /* sourcestate of the current thread, assuming we are in the native world */
216 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
217 #if defined(ENABLE_THREADS)
218 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
220 replace_gc_from_native(THREADOBJECT, NULL, NULL);
222 /* everyone is halted now, we consider ourselves running */
223 GC_ASSERT(!gc_running);
227 RT_TIMING_GET_TIME(time_suspend);
229 GC_LOG( heap_println_usage(); );
230 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
232 /* find the global and local rootsets */
233 rs = rootset_readout();
234 GC_LOG( rootset_print(rs); );
236 RT_TIMING_GET_TIME(time_rootset);
240 /* mark the objects considering the given rootset */
242 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
244 RT_TIMING_GET_TIME(time_mark);
246 /* compact the heap */
247 compact_me(rs, heap_region_main);
248 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
250 #if defined(ENABLE_MEMCHECK)
251 /* invalidate the rest of the main region */
252 region_invalidate(heap_region_main);
255 RT_TIMING_GET_TIME(time_compact);
257 /* check if we should increase the heap size */
258 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
259 heap_increase_size(rs);
263 /* copy the heap to new region */
265 regioninfo_t *src, *dst;
267 src = heap_region_main;
268 dst = NEW(regioninfo_t);
269 region_create(dst, heap_current_size);
270 copy_me(heap_region_main, dst, rs);
271 heap_region_main = dst;
273 /* invalidate old heap */
274 memset(src->base, 0x66, src->size);
278 /* TODO: check my return value! */
279 /*heap_increase_size();*/
281 /* write back the rootset to update root references */
282 GC_LOG( rootset_print(rs); );
283 rootset_writeback(rs);
285 #if defined(ENABLE_STATISTICS)
290 /* we are no longer running */
293 #if defined(ENABLE_THREADS)
294 /* start the world again */
295 GC_LOG( dolog("GC: Reanimating world ..."); );
296 threads_startworld();
297 /*GC_LOG( threads_dump(); );*/
300 #if defined(GCCONF_FINALIZER)
301 /* does the finalizer need to be notified */
302 if (gc_notify_finalizer)
306 RT_TIMING_GET_TIME(time_end);
308 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
309 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
310 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
311 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
312 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
313 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
315 /* free dump memory area */
316 dump_release(dumpsize);
318 /* leave the global gc lock */
319 LOCK_MONITOR_EXIT(gc_global_lock);
324 #if defined(ENABLE_THREADS)
325 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
329 /* check if the thread suspended itself */
331 GC_LOG( dolog("GC: Suspended myself!"); );
335 /* thread was forcefully suspended */
336 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
338 /* check where this thread came to a halt */
339 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
341 if (thread->gc_critical) {
342 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
346 /* wait till this thread suspends itself */
350 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
352 /* we assume we are in a native! */
353 replace_gc_from_native(thread, pc, sp);
361 code = code_find_codeinfo_for_pc_nocheck(pc);
364 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
367 /* arm the replacement points of the code this thread is in */
368 replace_activate_replacement_points(code, false);
370 /* wait till this thread suspends itself */
374 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
376 /* re-suspend me later */
377 /* TODO: implement me! */
378 /* TODO: (this is a rare race condition which was not yet triggered) */
386 /* this point should never be reached */
393 /* gc_call *********************************************************************
395 Forces a full collection of the whole Java Heap.
396 This is the function which is called by java.lang.Runtime.gc()
398 *******************************************************************************/
403 dolog("GC: Forced Collection ...");
405 GCSTAT_COUNT(gcstat_collections_forced);
410 dolog("GC: Forced Collection finished.");
414 /* gc_invoke_finalizers ********************************************************
416 Forces invocation of all the finalizers for objects which are reclaimable.
417 This is the function which is called by the finalizer thread.
419 *******************************************************************************/
421 void gc_invoke_finalizers(void)
424 dolog("GC: Invoking finalizers ...");
429 dolog("GC: Invoking finalizers finished.");
433 /* gc_finalize_all *************************************************************
435 Forces the finalization of all objects on the Java Heap.
436 This is the function which is called by java.lang.Runtime.exit()
438 We do this by setting all objects with finalizers to reclaimable,
439 which is inherently dangerouse because objects may still be alive.
441 *******************************************************************************/
443 void gc_finalize_all(void)
446 /* doing this is deprecated, inform the user */
447 dolog("gc_finalize_all: Deprecated!");
450 /* set all objects with finalizers to reclaimable */
451 final_set_all_reclaimable();
453 /* notify the finalizer thread */
458 /* Informational getter functions *********************************************/
460 s8 gc_get_heap_size(void) { return heap_current_size; }
461 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
462 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
463 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
466 /* Statistics *****************************************************************/
468 #if defined(ENABLE_STATISTICS)
469 int gcstat_collections;
470 int gcstat_collections_forced;
471 int gcstat_mark_depth;
472 int gcstat_mark_depth_max;
473 int gcstat_mark_count;
475 void gcstat_println()
477 printf("\nGCSTAT - General Statistics:\n");
478 printf("\t# of collections: %d\n", gcstat_collections);
479 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
481 printf("\nGCSTAT - Marking Statistics:\n");
482 printf("\t# of objects marked: %d\n", gcstat_mark_count);
483 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
485 printf("\nGCSTAT - Compaction Statistics:\n");
489 #endif /* defined(ENABLE_STATISTICS) */
493 * These are local overrides for various environment variables in Emacs.
494 * Please do not remove this and leave it at the end of the file, where
495 * Emacs will automagically detect them.
496 * ---------------------------------------------------------------------
499 * indent-tabs-mode: t
503 * vim:noexpandtab:sw=4:ts=4: