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 void gc_reference_unregister(java_objectheader **ref)
148 vm_abort("gc_reference_unregister: IMPLEMENT ME!");
152 /* gc_collect ******************************************************************
154 This is the main machinery which manages a collection. It should be run by
155 the thread which triggered the collection.
160 STEPS OF A COLLECTION:
163 *******************************************************************************/
165 void gc_collect(s4 level)
171 stacktracebuffer *stb;
173 #if defined(ENABLE_RT_TIMING)
174 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
177 /* enter the global gc lock */
178 LOCK_MONITOR_ENTER(gc_global_lock);
180 /* remember start of dump memory area */
181 dumpsize = dump_size();
183 GCSTAT_COUNT(gcstat_collections);
185 RT_TIMING_GET_TIME(time_start);
187 /* let everyone know we want to do a collection */
188 GC_ASSERT(!gc_pending);
191 /* finalizer is not notified, unless marking tells us to do so */
192 gc_notify_finalizer = false;
194 #if defined(ENABLE_THREADS)
195 /* stop the world here */
196 GC_LOG( dolog("GC: Suspending threads ..."); );
197 GC_LOG( threads_dump(); );
199 /*GC_LOG( threads_dump(); );*/
200 GC_LOG( dolog("GC: Suspension finished."); );
204 /* get the stacktrace of the current thread and make sure it is non-empty */
205 GC_LOG( printf("Stacktrace of current thread:\n"); );
206 sfi = STACKFRAMEINFO;
207 stb = stacktrace_create(sfi);
209 vm_abort("gc_collect: no stacktrace available for current thread!");
210 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
213 /* sourcestate of the current thread, assuming we are in the native world */
214 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
215 #if defined(ENABLE_THREADS)
216 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
218 replace_gc_from_native(THREADOBJECT, NULL, NULL);
220 /* everyone is halted now, we consider ourselves running */
221 GC_ASSERT(!gc_running);
225 RT_TIMING_GET_TIME(time_suspend);
227 GC_LOG( heap_println_usage(); );
228 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
230 /* find the global and local rootsets */
231 rs = rootset_readout();
232 GC_LOG( rootset_print(rs); );
234 RT_TIMING_GET_TIME(time_rootset);
238 /* mark the objects considering the given rootset */
240 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
242 RT_TIMING_GET_TIME(time_mark);
244 /* compact the heap */
245 compact_me(rs, heap_region_main);
246 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
248 #if defined(ENABLE_MEMCHECK)
249 /* invalidate the rest of the main region */
250 region_invalidate(heap_region_main);
253 RT_TIMING_GET_TIME(time_compact);
255 /* check if we should increase the heap size */
256 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
257 heap_increase_size(rs);
261 /* copy the heap to new region */
263 regioninfo_t *src, *dst;
265 src = heap_region_main;
266 dst = NEW(regioninfo_t);
267 region_create(dst, heap_current_size);
268 copy_me(heap_region_main, dst, rs);
269 heap_region_main = dst;
271 /* invalidate old heap */
272 memset(src->base, 0x66, src->size);
276 /* TODO: check my return value! */
277 /*heap_increase_size();*/
279 /* write back the rootset to update root references */
280 GC_LOG( rootset_print(rs); );
281 rootset_writeback(rs);
283 #if defined(ENABLE_STATISTICS)
288 /* we are no longer running */
291 #if defined(ENABLE_THREADS)
292 /* start the world again */
293 GC_LOG( dolog("GC: Reanimating world ..."); );
294 threads_startworld();
295 /*GC_LOG( threads_dump(); );*/
298 #if defined(GCCONF_FINALIZER)
299 /* does the finalizer need to be notified */
300 if (gc_notify_finalizer)
304 RT_TIMING_GET_TIME(time_end);
306 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
307 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
308 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
309 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
310 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
311 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
313 /* free dump memory area */
314 dump_release(dumpsize);
316 /* leave the global gc lock */
317 LOCK_MONITOR_EXIT(gc_global_lock);
322 #if defined(ENABLE_THREADS)
323 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
327 /* check if the thread suspended itself */
329 GC_LOG( dolog("GC: Suspended myself!"); );
333 /* thread was forcefully suspended */
334 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
336 /* check where this thread came to a halt */
337 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
339 if (thread->gc_critical) {
340 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
344 /* wait till this thread suspends itself */
348 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
350 /* we assume we are in a native! */
351 replace_gc_from_native(thread, pc, sp);
359 code = code_find_codeinfo_for_pc_nocheck(pc);
362 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
365 /* arm the replacement points of the code this thread is in */
366 replace_activate_replacement_points(code, false);
368 /* wait till this thread suspends itself */
372 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
374 /* re-suspend me later */
375 /* TODO: implement me! */
376 /* TODO: (this is a rare race condition which was not yet triggered) */
384 /* this point should never be reached */
391 /* gc_call *********************************************************************
393 Forces a full collection of the whole Java Heap.
394 This is the function which is called by java.lang.Runtime.gc()
396 *******************************************************************************/
401 dolog("GC: Forced Collection ...");
403 GCSTAT_COUNT(gcstat_collections_forced);
408 dolog("GC: Forced Collection finished.");
412 /* gc_invoke_finalizers ********************************************************
414 Forces invocation of all the finalizers for objects which are reclaimable.
415 This is the function which is called by the finalizer thread.
417 *******************************************************************************/
419 void gc_invoke_finalizers(void)
422 dolog("GC: Invoking finalizers ...");
427 dolog("GC: Invoking finalizers finished.");
431 /* gc_finalize_all *************************************************************
433 Forces the finalization of all objects on the Java Heap.
434 This is the function which is called by java.lang.Runtime.exit()
436 We do this by setting all objects with finalizers to reclaimable,
437 which is inherently dangerouse because objects may still be alive.
439 *******************************************************************************/
441 void gc_finalize_all(void)
444 /* doing this is deprecated, inform the user */
445 dolog("gc_finalize_all: Deprecated!");
448 /* set all objects with finalizers to reclaimable */
449 final_set_all_reclaimable();
451 /* notify the finalizer thread */
456 /* Informational getter functions *********************************************/
458 s8 gc_get_heap_size(void) { return heap_current_size; }
459 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
460 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
461 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
464 /* Statistics *****************************************************************/
466 #if defined(ENABLE_STATISTICS)
467 int gcstat_collections;
468 int gcstat_collections_forced;
469 int gcstat_mark_depth;
470 int gcstat_mark_depth_max;
471 int gcstat_mark_count;
473 void gcstat_println()
475 printf("\nGCSTAT - General Statistics:\n");
476 printf("\t# of collections: %d\n", gcstat_collections);
477 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
479 printf("\nGCSTAT - Marking Statistics:\n");
480 printf("\t# of objects marked: %d\n", gcstat_mark_count);
481 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
483 printf("\nGCSTAT - Compaction Statistics:\n");
487 #endif /* defined(ENABLE_STATISTICS) */
491 * These are local overrides for various environment variables in Emacs.
492 * Please do not remove this and leave it at the end of the file, where
493 * Emacs will automagically detect them.
494 * ---------------------------------------------------------------------
497 * indent-tabs-mode: t
501 * vim:noexpandtab:sw=4:ts=4: