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
32 #include "threads/lock-common.h"
33 #include "threads/threads-common.h"
43 #include "mm/memory.h"
44 #include "toolbox/logging.h"
45 #include "vm/finalizer.h"
47 #include "vmcore/rt-timing.h"
50 /* Global Variables ***********************************************************/
54 bool gc_notify_finalizer;
56 list_t *gc_reflist_strong;
57 list_t *gc_reflist_weak;
59 #if defined(ENABLE_THREADS)
60 java_object_t *gc_global_lock;
63 #if !defined(ENABLE_THREADS)
64 executionstate_t *_no_threads_executionstate;
65 sourcestate_t *_no_threads_sourcestate;
69 /* gc_init *********************************************************************
71 Initializes the garbage collector.
73 *******************************************************************************/
75 #define GC_SYS_SIZE (20*1024*1024)
77 void gc_init(u4 heapmaxsize, u4 heapstartsize)
80 dolog("GC: Initialising with heap-size %d (max. %d)",
81 heapstartsize, heapmaxsize);
83 #if defined(ENABLE_HANDLES)
84 /* check our indirection cells */
85 if (OFFSET(java_handle_t, heap_object) != 0)
86 vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
87 if (OFFSET(hashtable_classloader_entry, object) != 0)
88 vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
89 if (OFFSET(hashtable_global_ref_entry, o) != 0)
90 vm_abort("gc_init: global reference entry cannot be used as indirection cell: %d", OFFSET(hashtable_global_ref_entry, o));
96 /* set global variables */
100 /* create list for external references */
101 gc_reflist_strong = list_create(OFFSET(list_gcref_entry_t, linkage));
102 gc_reflist_weak = list_create(OFFSET(list_gcref_entry_t, linkage));
104 #if defined(ENABLE_THREADS)
105 /* create global gc lock object */
106 gc_global_lock = NEW(java_object_t);
107 lock_init_object_lock(gc_global_lock);
110 /* region for uncollectable objects */
111 heap_region_sys = NEW(regioninfo_t);
112 if (!region_create(heap_region_sys, GC_SYS_SIZE))
113 vm_abort("gc_init: region_create failed: out of memory");
115 /* region for java objects */
116 heap_region_main = NEW(regioninfo_t);
117 if (!region_create(heap_region_main, heapstartsize))
118 vm_abort("gc_init: region_create failed: out of memory");
120 heap_current_size = heapstartsize;
121 heap_maximal_size = heapmaxsize;
125 /* gc_reference_register *******************************************************
127 Register an external reference which points onto the Heap and keeps
128 objects alive (strong reference).
130 *******************************************************************************/
132 static void gc_reference_register_intern(list_t *list, java_object_t **ref, int32_t reftype)
134 list_gcref_entry_t *re;
136 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
138 /* the reference needs to be registered before it is set, so make sure the
139 reference is not yet set */
140 GC_ASSERT(*ref == NULL);
142 re = NEW(list_gcref_entry_t);
146 re->reftype = reftype;
149 list_add_last(list, re);
152 static void gc_reference_unregister_intern(list_t *list, java_object_t **ref)
154 list_gcref_entry_t *re;
156 GC_LOG2( printf("Un-Registering Reference at %p\n", (void *) ref); );
158 for (re = list_first(list); re != NULL; re = list_next(list, re)) {
159 if (re->ref == ref) {
160 list_remove(list, re);
162 FREE(re, list_gcref_entry_t);
171 void gc_reference_register(java_object_t **ref, int32_t reftype)
173 #if defined(ENABLE_THREADS)
174 /* XXX dirty hack because threads_init() not yet called */
175 if (THREADOBJECT == NULL) {
176 GC_LOG( dolog("GC: Unable to register Reference!"); );
181 gc_reference_register_intern(gc_reflist_strong, ref, reftype);
184 void gc_weakreference_register(java_object_t **ref, int32_t reftype)
186 gc_reference_register_intern(gc_reflist_weak, ref, reftype);
189 void gc_reference_unregister(java_object_t **ref)
191 gc_reference_unregister_intern(gc_reflist_strong, ref);
194 void gc_weakreference_unregister(java_object_t **ref)
196 gc_reference_unregister_intern(gc_reflist_weak, ref);
200 /* gc_collect ******************************************************************
202 This is the main machinery which manages a collection. It should be run by
203 the thread which triggered the collection.
208 STEPS OF A COLLECTION:
211 *******************************************************************************/
213 void gc_collect(s4 level)
219 stacktracebuffer *stb;
221 #if defined(ENABLE_RT_TIMING)
222 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
225 /* enter the global gc lock */
226 LOCK_MONITOR_ENTER(gc_global_lock);
228 /* remember start of dump memory area */
229 dumpsize = dump_size();
231 GCSTAT_COUNT(gcstat_collections);
233 RT_TIMING_GET_TIME(time_start);
235 /* let everyone know we want to do a collection */
236 GC_ASSERT(!gc_pending);
239 /* finalizer is not notified, unless marking tells us to do so */
240 gc_notify_finalizer = false;
242 #if defined(ENABLE_THREADS)
243 /* stop the world here */
244 GC_LOG( dolog("GC: Suspending threads ..."); );
245 GC_LOG( threads_dump(); );
247 /*GC_LOG( threads_dump(); );*/
248 GC_LOG( dolog("GC: Suspension finished."); );
252 /* get the stacktrace of the current thread and make sure it is non-empty */
253 GC_LOG( printf("Stacktrace of current thread:\n"); );
254 sfi = STACKFRAMEINFO;
255 stb = stacktrace_create(sfi);
257 vm_abort("gc_collect: no stacktrace available for current thread!");
258 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
261 /* sourcestate of the current thread, assuming we are in the native world */
262 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
263 #if defined(ENABLE_THREADS)
264 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
266 replace_gc_from_native(THREADOBJECT, NULL, NULL);
268 /* everyone is halted now, we consider ourselves running */
269 GC_ASSERT(!gc_running);
273 RT_TIMING_GET_TIME(time_suspend);
275 GC_LOG( heap_println_usage(); );
276 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
278 /* find the global and local rootsets */
279 rs = rootset_readout();
282 /* print the rootsets if debugging is enabled */
283 if (opt_GCDebugRootSet)
287 RT_TIMING_GET_TIME(time_rootset);
291 /* mark the objects considering the given rootset */
293 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
295 RT_TIMING_GET_TIME(time_mark);
297 /* compact the heap */
298 compact_me(rs, heap_region_main);
299 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
301 #if defined(ENABLE_MEMCHECK)
302 /* invalidate the rest of the main region */
303 region_invalidate(heap_region_main);
306 RT_TIMING_GET_TIME(time_compact);
308 /* check if we should increase the heap size */
309 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
310 heap_increase_size(rs);
314 /* copy the heap to new region */
316 regioninfo_t *src, *dst;
318 src = heap_region_main;
319 dst = NEW(regioninfo_t);
320 region_create(dst, heap_current_size);
321 copy_me(heap_region_main, dst, rs);
322 heap_region_main = dst;
324 /* invalidate old heap */
325 memset(src->base, 0x66, src->size);
329 /* TODO: check my return value! */
330 /*heap_increase_size();*/
332 /* write back the rootset to update root references */
333 GC_LOG( rootset_print(rs); );
334 rootset_writeback(rs);
336 #if defined(ENABLE_STATISTICS)
341 /* we are no longer running */
344 #if defined(ENABLE_THREADS)
345 /* start the world again */
346 GC_LOG( dolog("GC: Reanimating world ..."); );
347 threads_startworld();
348 /*GC_LOG( threads_dump(); );*/
351 #if defined(GCCONF_FINALIZER)
352 /* does the finalizer need to be notified */
353 if (gc_notify_finalizer)
357 RT_TIMING_GET_TIME(time_end);
359 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
360 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
361 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
362 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
363 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
364 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
366 /* free dump memory area */
367 dump_release(dumpsize);
369 /* leave the global gc lock */
370 LOCK_MONITOR_EXIT(gc_global_lock);
372 /* XXX move this to an appropriate place */
373 lock_hashtable_cleanup();
377 #if defined(ENABLE_THREADS)
378 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
382 /* check if the thread suspended itself */
384 GC_LOG( dolog("GC: Suspended myself!"); );
388 /* thread was forcefully suspended */
389 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
391 /* check where this thread came to a halt */
392 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
394 if (thread->gc_critical) {
395 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
399 /* wait till this thread suspends itself */
403 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
405 /* we assume we are in a native! */
406 replace_gc_from_native(thread, pc, sp);
414 code = code_find_codeinfo_for_pc_nocheck(pc);
417 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
420 /* arm the replacement points of the code this thread is in */
421 replace_activate_replacement_points(code, false);
423 /* wait till this thread suspends itself */
427 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
429 /* re-suspend me later */
430 /* TODO: implement me! */
431 /* TODO: (this is a rare race condition which was not yet triggered) */
439 /* this point should never be reached */
446 /* gc_call *********************************************************************
448 Forces a full collection of the whole Java Heap.
449 This is the function which is called by java.lang.Runtime.gc()
451 *******************************************************************************/
456 dolog("GC: Forced Collection ...");
458 GCSTAT_COUNT(gcstat_collections_forced);
463 dolog("GC: Forced Collection finished.");
467 /* gc_invoke_finalizers ********************************************************
469 Forces invocation of all the finalizers for objects which are reclaimable.
470 This is the function which is called by the finalizer thread.
472 *******************************************************************************/
474 void gc_invoke_finalizers(void)
477 dolog("GC: Invoking finalizers ...");
482 dolog("GC: Invoking finalizers finished.");
486 /* gc_finalize_all *************************************************************
488 Forces the finalization of all objects on the Java Heap.
489 This is the function which is called by java.lang.Runtime.exit()
491 We do this by setting all objects with finalizers to reclaimable,
492 which is inherently dangerouse because objects may still be alive.
494 *******************************************************************************/
496 void gc_finalize_all(void)
499 /* doing this is deprecated, inform the user */
500 dolog("gc_finalize_all: Deprecated!");
503 /* set all objects with finalizers to reclaimable */
504 final_set_all_reclaimable();
506 /* notify the finalizer thread */
511 /* Informational getter functions *********************************************/
513 s8 gc_get_heap_size(void) { return heap_current_size; }
514 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
515 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
516 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
519 /* Statistics *****************************************************************/
521 #if defined(ENABLE_STATISTICS)
522 int gcstat_collections;
523 int gcstat_collections_forced;
524 int gcstat_mark_depth;
525 int gcstat_mark_depth_max;
526 int gcstat_mark_count;
528 void gcstat_println()
530 printf("\nGCSTAT - General Statistics:\n");
531 printf("\t# of collections: %d\n", gcstat_collections);
532 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
534 printf("\nGCSTAT - Marking Statistics:\n");
535 printf("\t# of objects marked: %d\n", gcstat_mark_count);
536 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
538 printf("\nGCSTAT - Compaction Statistics:\n");
542 #endif /* defined(ENABLE_STATISTICS) */
546 * These are local overrides for various environment variables in Emacs.
547 * Please do not remove this and leave it at the end of the file, where
548 * Emacs will automagically detect them.
549 * ---------------------------------------------------------------------
552 * indent-tabs-mode: t
556 * vim:noexpandtab:sw=4:ts=4: