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_object_t *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);
84 #if defined(ENABLE_HANDLES)
85 /* check our indirection cells */
86 if (OFFSET(java_handle_t, heap_object) != 0)
87 vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
88 if (OFFSET(hashtable_classloader_entry, object) != 0)
89 vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
95 /* set global variables */
99 /* create list for external references */
100 gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
102 #if defined(ENABLE_THREADS)
103 /* create global gc lock object */
104 gc_global_lock = NEW(java_object_t);
105 lock_init_object_lock(gc_global_lock);
108 /* region for uncollectable objects */
109 heap_region_sys = NEW(regioninfo_t);
110 if (!region_create(heap_region_sys, GC_SYS_SIZE))
111 vm_abort("gc_init: region_create failed: out of memory");
113 /* region for java objects */
114 heap_region_main = NEW(regioninfo_t);
115 if (!region_create(heap_region_main, heapstartsize))
116 vm_abort("gc_init: region_create failed: out of memory");
118 heap_current_size = heapstartsize;
119 heap_maximal_size = heapmaxsize;
123 /* gc_reference_register *******************************************************
125 Register an external reference which points onto the Heap and keeps
126 objects alive (strong reference).
128 *******************************************************************************/
130 void gc_reference_register(java_object_t **ref)
132 list_gcref_entry_t *re;
134 /* the reference needs to be registered before it is set, so make sure the
135 reference is not yet set */
136 GC_ASSERT(*ref == NULL);
138 #if defined(ENABLE_THREADS)
139 /* XXX dirty hack because threads_init() not yet called */
140 if (THREADOBJECT == NULL) {
141 GC_LOG( dolog("GC: Unable to register Reference!"); );
146 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
148 re = NEW(list_gcref_entry_t);
152 list_add_last(gc_reflist, re);
156 void gc_reference_unregister(java_object_t **ref)
158 vm_abort("gc_reference_unregister: IMPLEMENT ME!");
162 /* gc_collect ******************************************************************
164 This is the main machinery which manages a collection. It should be run by
165 the thread which triggered the collection.
170 STEPS OF A COLLECTION:
173 *******************************************************************************/
175 void gc_collect(s4 level)
181 stacktracebuffer *stb;
183 #if defined(ENABLE_RT_TIMING)
184 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
187 /* enter the global gc lock */
188 LOCK_MONITOR_ENTER(gc_global_lock);
190 /* remember start of dump memory area */
191 dumpsize = dump_size();
193 GCSTAT_COUNT(gcstat_collections);
195 RT_TIMING_GET_TIME(time_start);
197 /* let everyone know we want to do a collection */
198 GC_ASSERT(!gc_pending);
201 /* finalizer is not notified, unless marking tells us to do so */
202 gc_notify_finalizer = false;
204 #if defined(ENABLE_THREADS)
205 /* stop the world here */
206 GC_LOG( dolog("GC: Suspending threads ..."); );
207 GC_LOG( threads_dump(); );
209 /*GC_LOG( threads_dump(); );*/
210 GC_LOG( dolog("GC: Suspension finished."); );
214 /* get the stacktrace of the current thread and make sure it is non-empty */
215 GC_LOG( printf("Stacktrace of current thread:\n"); );
216 sfi = STACKFRAMEINFO;
217 stb = stacktrace_create(sfi);
219 vm_abort("gc_collect: no stacktrace available for current thread!");
220 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
223 /* sourcestate of the current thread, assuming we are in the native world */
224 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
225 #if defined(ENABLE_THREADS)
226 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
228 replace_gc_from_native(THREADOBJECT, NULL, NULL);
230 /* everyone is halted now, we consider ourselves running */
231 GC_ASSERT(!gc_running);
235 RT_TIMING_GET_TIME(time_suspend);
237 GC_LOG( heap_println_usage(); );
238 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
240 /* find the global and local rootsets */
241 rs = rootset_readout();
242 GC_LOG( rootset_print(rs); );
244 RT_TIMING_GET_TIME(time_rootset);
248 /* mark the objects considering the given rootset */
250 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
252 RT_TIMING_GET_TIME(time_mark);
254 /* compact the heap */
255 compact_me(rs, heap_region_main);
256 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
258 #if defined(ENABLE_MEMCHECK)
259 /* invalidate the rest of the main region */
260 region_invalidate(heap_region_main);
263 RT_TIMING_GET_TIME(time_compact);
265 /* check if we should increase the heap size */
266 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
267 heap_increase_size(rs);
271 /* copy the heap to new region */
273 regioninfo_t *src, *dst;
275 src = heap_region_main;
276 dst = NEW(regioninfo_t);
277 region_create(dst, heap_current_size);
278 copy_me(heap_region_main, dst, rs);
279 heap_region_main = dst;
281 /* invalidate old heap */
282 memset(src->base, 0x66, src->size);
286 /* TODO: check my return value! */
287 /*heap_increase_size();*/
289 /* write back the rootset to update root references */
290 GC_LOG( rootset_print(rs); );
291 rootset_writeback(rs);
293 #if defined(ENABLE_STATISTICS)
298 /* we are no longer running */
301 #if defined(ENABLE_THREADS)
302 /* start the world again */
303 GC_LOG( dolog("GC: Reanimating world ..."); );
304 threads_startworld();
305 /*GC_LOG( threads_dump(); );*/
308 #if defined(GCCONF_FINALIZER)
309 /* does the finalizer need to be notified */
310 if (gc_notify_finalizer)
314 RT_TIMING_GET_TIME(time_end);
316 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
317 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
318 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
319 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
320 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
321 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
323 /* free dump memory area */
324 dump_release(dumpsize);
326 /* leave the global gc lock */
327 LOCK_MONITOR_EXIT(gc_global_lock);
332 #if defined(ENABLE_THREADS)
333 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
337 /* check if the thread suspended itself */
339 GC_LOG( dolog("GC: Suspended myself!"); );
343 /* thread was forcefully suspended */
344 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
346 /* check where this thread came to a halt */
347 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
349 if (thread->gc_critical) {
350 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
354 /* wait till this thread suspends itself */
358 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
360 /* we assume we are in a native! */
361 replace_gc_from_native(thread, pc, sp);
369 code = code_find_codeinfo_for_pc_nocheck(pc);
372 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
375 /* arm the replacement points of the code this thread is in */
376 replace_activate_replacement_points(code, false);
378 /* wait till this thread suspends itself */
382 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
384 /* re-suspend me later */
385 /* TODO: implement me! */
386 /* TODO: (this is a rare race condition which was not yet triggered) */
394 /* this point should never be reached */
401 /* gc_call *********************************************************************
403 Forces a full collection of the whole Java Heap.
404 This is the function which is called by java.lang.Runtime.gc()
406 *******************************************************************************/
411 dolog("GC: Forced Collection ...");
413 GCSTAT_COUNT(gcstat_collections_forced);
418 dolog("GC: Forced Collection finished.");
422 /* gc_invoke_finalizers ********************************************************
424 Forces invocation of all the finalizers for objects which are reclaimable.
425 This is the function which is called by the finalizer thread.
427 *******************************************************************************/
429 void gc_invoke_finalizers(void)
432 dolog("GC: Invoking finalizers ...");
437 dolog("GC: Invoking finalizers finished.");
441 /* gc_finalize_all *************************************************************
443 Forces the finalization of all objects on the Java Heap.
444 This is the function which is called by java.lang.Runtime.exit()
446 We do this by setting all objects with finalizers to reclaimable,
447 which is inherently dangerouse because objects may still be alive.
449 *******************************************************************************/
451 void gc_finalize_all(void)
454 /* doing this is deprecated, inform the user */
455 dolog("gc_finalize_all: Deprecated!");
458 /* set all objects with finalizers to reclaimable */
459 final_set_all_reclaimable();
461 /* notify the finalizer thread */
466 /* Informational getter functions *********************************************/
468 s8 gc_get_heap_size(void) { return heap_current_size; }
469 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
470 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
471 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
474 /* Statistics *****************************************************************/
476 #if defined(ENABLE_STATISTICS)
477 int gcstat_collections;
478 int gcstat_collections_forced;
479 int gcstat_mark_depth;
480 int gcstat_mark_depth_max;
481 int gcstat_mark_count;
483 void gcstat_println()
485 printf("\nGCSTAT - General Statistics:\n");
486 printf("\t# of collections: %d\n", gcstat_collections);
487 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
489 printf("\nGCSTAT - Marking Statistics:\n");
490 printf("\t# of objects marked: %d\n", gcstat_mark_count);
491 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
493 printf("\nGCSTAT - Compaction Statistics:\n");
497 #endif /* defined(ENABLE_STATISTICS) */
501 * These are local overrides for various environment variables in Emacs.
502 * Please do not remove this and leave it at the end of the file, where
503 * Emacs will automagically detect them.
504 * ---------------------------------------------------------------------
507 * indent-tabs-mode: t
511 * vim:noexpandtab:sw=4:ts=4: