1 /* src/mm/cacao-gc/gc.c - main garbage collector methods
3 Copyright (C) 2006, 2007, 2008
4 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
6 This file is part of CACAO.
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
33 #include "threads/lock-common.h"
34 #include "threads/thread.h"
44 #include "mm/memory.h"
45 #include "toolbox/logging.h"
46 #include "vm/finalizer.h"
48 #include "vmcore/rt-timing.h"
51 /* Global Variables ***********************************************************/
55 bool gc_notify_finalizer;
57 list_t *gc_reflist_strong;
58 list_t *gc_reflist_weak;
60 #if !defined(ENABLE_THREADS)
61 executionstate_t *_no_threads_executionstate;
62 sourcestate_t *_no_threads_sourcestate;
66 /* gc_init *********************************************************************
68 Initializes the garbage collector.
70 *******************************************************************************/
72 #define GC_SYS_SIZE (20*1024*1024)
74 void gc_init(u4 heapmaxsize, u4 heapstartsize)
77 dolog("GC: Initialising with heap-size %d (max. %d)",
78 heapstartsize, heapmaxsize);
80 #if defined(ENABLE_HANDLES)
81 /* check our indirection cells */
82 if (OFFSET(java_handle_t, heap_object) != 0)
83 vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
84 if (OFFSET(hashtable_classloader_entry, object) != 0)
85 vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
86 if (OFFSET(hashtable_global_ref_entry, o) != 0)
87 vm_abort("gc_init: global reference entry cannot be used as indirection cell: %d", OFFSET(hashtable_global_ref_entry, o));
93 /* set global variables */
97 /* create list for external references */
98 gc_reflist_strong = list_create(OFFSET(list_gcref_entry_t, linkage));
99 gc_reflist_weak = list_create(OFFSET(list_gcref_entry_t, linkage));
101 /* region for uncollectable objects */
102 heap_region_sys = NEW(regioninfo_t);
103 if (!region_create(heap_region_sys, GC_SYS_SIZE))
104 vm_abort("gc_init: region_create failed: out of memory");
106 /* region for java objects */
107 heap_region_main = NEW(regioninfo_t);
108 if (!region_create(heap_region_main, heapstartsize))
109 vm_abort("gc_init: region_create failed: out of memory");
111 heap_current_size = heapstartsize;
112 heap_maximal_size = heapmaxsize;
116 /* gc_reference_register *******************************************************
118 Register an external reference which points onto the Heap. The
119 reference needs to be cleared (set to NULL) when registering and
120 has to be set after it has been registered (to avoid a race condition).
122 STRONG REFERENCE: gets updated and keeps objects alive
123 WEAK REFERENCE: only gets updated (or maybe cleared)
125 *******************************************************************************/
127 static void gc_reference_register_intern(list_t *list, java_object_t **ref, int32_t reftype)
129 list_gcref_entry_t *re;
131 /* the global GC lock also guards the reference lists */
134 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
136 /* the reference needs to be registered before it is set, so make sure the
137 reference is not yet set */
138 GC_ASSERT(*ref == NULL);
141 /* check if this reference is already registered */
142 for (re = list_first(list); re != NULL; re = list_next(list, re)) {
144 vm_abort("gc_reference_register_intern: reference already registered");
148 /* create a new reference entry */
149 re = NEW(list_gcref_entry_t);
153 re->reftype = reftype;
156 /* add the entry to the given list */
157 list_add_last(list, re);
159 /* the global GC lock also guards the reference lists */
163 void gc_reference_register(java_object_t **ref, int32_t reftype)
165 gc_reference_register_intern(gc_reflist_strong, ref, reftype);
168 void gc_weakreference_register(java_object_t **ref, int32_t reftype)
170 gc_reference_register_intern(gc_reflist_weak, ref, reftype);
174 /* gc_reference_unregister *****************************************************
176 Unregister a previously registered external reference.
178 *******************************************************************************/
180 static void gc_reference_unregister_intern(list_t *list, java_object_t **ref)
182 list_gcref_entry_t *re;
184 /* the global GC lock also guards the reference lists */
187 GC_LOG2( printf("Un-Registering Reference at %p\n", (void *) ref); );
189 /* search for the appropriate reference entry */
190 for (re = list_first(list); re != NULL; re = list_next(list, re)) {
191 if (re->ref == ref) {
192 /* remove the entry from the given list */
193 list_remove(list, re);
195 /* free the reference entry */
196 FREE(re, list_gcref_entry_t);
202 vm_abort("gc_reference_unregister_intern: reference not found");
204 /* the global GC lock also guards the reference lists */
208 void gc_reference_unregister(java_object_t **ref)
210 gc_reference_unregister_intern(gc_reflist_strong, ref);
213 void gc_weakreference_unregister(java_object_t **ref)
215 gc_reference_unregister_intern(gc_reflist_weak, ref);
219 /* gc_collect ******************************************************************
221 This is the main machinery which manages a collection. It should be run by
222 the thread which triggered the collection.
227 STEPS OF A COLLECTION:
230 *******************************************************************************/
232 void gc_collect(s4 level)
239 #if defined(ENABLE_RT_TIMING)
240 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
243 /* enter the global gc lock */
246 /* remember start of dump memory area */
249 GCSTAT_COUNT(gcstat_collections);
251 RT_TIMING_GET_TIME(time_start);
253 /* let everyone know we want to do a collection */
254 GC_ASSERT(!gc_pending);
257 /* finalizer is not notified, unless marking tells us to do so */
258 gc_notify_finalizer = false;
260 #if defined(ENABLE_THREADS)
261 /* stop the world here */
262 GC_LOG( dolog("GC: Suspending threads ..."); );
263 GC_LOG( threads_dump(); );
265 /*GC_LOG( threads_dump(); );*/
266 GC_LOG( dolog("GC: Suspension finished."); );
270 /* get the stacktrace of the current thread and make sure it is non-empty */
271 GC_LOG( printf("Stacktrace of current thread:\n"); );
272 st = stacktrace_get_current();
274 vm_abort("gc_collect: no stacktrace available for current thread!");
275 GC_LOG( stacktrace_print(st); );
278 /* sourcestate of the current thread, assuming we are in the native world */
279 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
280 #if defined(ENABLE_THREADS)
281 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
283 replace_gc_from_native(THREADOBJECT, NULL, NULL);
285 /* everyone is halted now, we consider ourselves running */
286 GC_ASSERT(!gc_running);
290 RT_TIMING_GET_TIME(time_suspend);
292 GC_LOG( heap_println_usage(); );
293 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
295 /* find the global and local rootsets */
296 rs = rootset_readout();
299 /* print the rootsets if debugging is enabled */
300 if (opt_GCDebugRootSet)
304 RT_TIMING_GET_TIME(time_rootset);
308 /* mark the objects considering the given rootset */
310 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
312 RT_TIMING_GET_TIME(time_mark);
314 /* compact the heap */
315 compact_me(rs, heap_region_main);
316 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
318 #if defined(ENABLE_MEMCHECK)
319 /* invalidate the rest of the main region */
320 region_invalidate(heap_region_main);
323 RT_TIMING_GET_TIME(time_compact);
325 /* check if we should increase the heap size */
326 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
327 heap_increase_size(rs);
331 /* copy the heap to new region */
333 regioninfo_t *src, *dst;
335 src = heap_region_main;
336 dst = NEW(regioninfo_t);
337 region_create(dst, heap_current_size);
338 copy_me(heap_region_main, dst, rs);
339 heap_region_main = dst;
341 /* invalidate old heap */
342 memset(src->base, 0x66, src->size);
346 /* TODO: check my return value! */
347 /*heap_increase_size();*/
349 /* write back the rootset to update root references */
350 GC_LOG( rootset_print(rs); );
351 rootset_writeback(rs);
353 #if defined(ENABLE_STATISTICS)
358 /* we are no longer running */
361 #if defined(ENABLE_THREADS)
362 /* start the world again */
363 GC_LOG( dolog("GC: Reanimating world ..."); );
364 threads_startworld();
365 /*GC_LOG( threads_dump(); );*/
368 #if defined(GCCONF_FINALIZER)
369 /* does the finalizer need to be notified */
370 if (gc_notify_finalizer)
374 RT_TIMING_GET_TIME(time_end);
376 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
377 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
378 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
379 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
380 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
381 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
383 /* free dump memory area */
386 /* leave the global gc lock */
389 /* XXX move this to an appropriate place */
390 lock_hashtable_cleanup();
394 #if defined(ENABLE_THREADS)
395 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
399 /* check if the thread suspended itself */
401 GC_LOG( dolog("GC: Suspended myself!"); );
405 /* thread was forcefully suspended */
406 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
408 /* check where this thread came to a halt */
409 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
411 if (thread->gc_critical) {
412 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
416 /* wait till this thread suspends itself */
420 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
422 /* we assume we are in a native! */
423 replace_gc_from_native(thread, pc, sp);
431 code = code_find_codeinfo_for_pc_nocheck(pc);
434 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
437 /* arm the replacement points of the code this thread is in */
438 replace_activate_replacement_points(code, false);
440 /* wait till this thread suspends itself */
444 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
446 /* re-suspend me later */
447 /* TODO: implement me! */
448 /* TODO: (this is a rare race condition which was not yet triggered) */
456 /* this point should never be reached */
463 /* gc_call *********************************************************************
465 Forces a full collection of the whole Java Heap.
466 This is the function which is called by java.lang.Runtime.gc()
468 *******************************************************************************/
473 dolog("GC: Forced Collection ...");
475 GCSTAT_COUNT(gcstat_collections_forced);
480 dolog("GC: Forced Collection finished.");
484 /* gc_invoke_finalizers ********************************************************
486 Forces invocation of all the finalizers for objects which are reclaimable.
487 This is the function which is called by the finalizer thread.
489 *******************************************************************************/
491 void gc_invoke_finalizers(void)
494 dolog("GC: Invoking finalizers ...");
499 dolog("GC: Invoking finalizers finished.");
503 /* gc_finalize_all *************************************************************
505 Forces the finalization of all objects on the Java Heap.
506 This is the function which is called by java.lang.Runtime.exit()
508 We do this by setting all objects with finalizers to reclaimable,
509 which is inherently dangerouse because objects may still be alive.
511 *******************************************************************************/
513 void gc_finalize_all(void)
516 /* doing this is deprecated, inform the user */
517 dolog("gc_finalize_all: Deprecated!");
520 /* set all objects with finalizers to reclaimable */
521 final_set_all_reclaimable();
523 /* notify the finalizer thread */
528 /* Informational getter functions *********************************************/
530 s8 gc_get_heap_size(void) { return heap_current_size; }
531 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
532 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
533 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
536 /* Statistics *****************************************************************/
538 #if defined(ENABLE_STATISTICS)
539 int gcstat_collections;
540 int gcstat_collections_forced;
541 int gcstat_mark_depth;
542 int gcstat_mark_depth_max;
543 int gcstat_mark_count;
545 void gcstat_println()
547 printf("\nGCSTAT - General Statistics:\n");
548 printf("\t# of collections: %d\n", gcstat_collections);
549 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
551 printf("\nGCSTAT - Marking Statistics:\n");
552 printf("\t# of objects marked: %d\n", gcstat_mark_count);
553 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
555 printf("\nGCSTAT - Compaction Statistics:\n");
559 #endif /* defined(ENABLE_STATISTICS) */
563 * These are local overrides for various environment variables in Emacs.
564 * Please do not remove this and leave it at the end of the file, where
565 * Emacs will automagically detect them.
566 * ---------------------------------------------------------------------
569 * indent-tabs-mode: t
573 * vim:noexpandtab:sw=4:ts=4: