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.hpp"
34 #include "threads/thread.hpp"
44 #include "mm/memory.hpp"
45 #include "toolbox/logging.hpp"
47 #include "vm/finalizer.hpp"
48 #include "vm/rt-timing.h"
52 /* Global Variables ***********************************************************/
56 bool gc_notify_finalizer;
58 list_t *gc_reflist_strong;
59 list_t *gc_reflist_weak;
61 #if !defined(ENABLE_THREADS)
62 executionstate_t *_no_threads_executionstate;
63 sourcestate_t *_no_threads_sourcestate;
67 /* gc_init *********************************************************************
69 Initializes the garbage collector.
71 *******************************************************************************/
73 #define GC_SYS_SIZE (20*1024*1024)
75 void gc_init(u4 heapmaxsize, u4 heapstartsize)
78 dolog("GC: Initialising with heap-size %d (max. %d)",
79 heapstartsize, heapmaxsize);
81 #if defined(ENABLE_HANDLES)
82 /* check our indirection cells */
83 if (OFFSET(java_handle_t, heap_object) != 0)
84 vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
85 if (OFFSET(hashtable_classloader_entry, object) != 0)
86 vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
87 if (OFFSET(hashtable_global_ref_entry, o) != 0)
88 vm_abort("gc_init: global reference entry cannot be used as indirection cell: %d", OFFSET(hashtable_global_ref_entry, o));
94 /* set global variables */
98 /* create list for external references */
99 gc_reflist_strong = list_create(OFFSET(list_gcref_entry_t, linkage));
100 gc_reflist_weak = list_create(OFFSET(list_gcref_entry_t, linkage));
102 /* region for uncollectable objects */
103 heap_region_sys = NEW(regioninfo_t);
104 if (!region_create(heap_region_sys, GC_SYS_SIZE))
105 vm_abort("gc_init: region_create failed: out of memory");
107 /* region for java objects */
108 heap_region_main = NEW(regioninfo_t);
109 if (!region_create(heap_region_main, heapstartsize))
110 vm_abort("gc_init: region_create failed: out of memory");
112 heap_current_size = heapstartsize;
113 heap_maximal_size = heapmaxsize;
117 /* gc_reference_register *******************************************************
119 Register an external reference which points onto the Heap. The
120 reference needs to be cleared (set to NULL) when registering and
121 has to be set after it has been registered (to avoid a race condition).
123 STRONG REFERENCE: gets updated and keeps objects alive
124 WEAK REFERENCE: only gets updated (or maybe cleared)
126 *******************************************************************************/
128 static void gc_reference_register_intern(list_t *list, java_object_t **ref, int32_t reftype)
130 list_gcref_entry_t *re;
132 /* the global GC lock also guards the reference lists */
135 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
137 /* the reference needs to be registered before it is set, so make sure the
138 reference is not yet set */
139 GC_ASSERT(*ref == NULL);
142 /* check if this reference is already registered */
143 for (re = list_first(list); re != NULL; re = list_next(list, re)) {
145 vm_abort("gc_reference_register_intern: reference already registered");
149 /* create a new reference entry */
150 re = NEW(list_gcref_entry_t);
154 re->reftype = reftype;
157 /* add the entry to the given list */
158 list_add_last(list, re);
160 /* the global GC lock also guards the reference lists */
164 void gc_reference_register(java_object_t **ref, int32_t reftype)
166 gc_reference_register_intern(gc_reflist_strong, ref, reftype);
169 void gc_weakreference_register(java_object_t **ref, int32_t reftype)
171 gc_reference_register_intern(gc_reflist_weak, ref, reftype);
175 /* gc_reference_unregister *****************************************************
177 Unregister a previously registered external reference.
179 *******************************************************************************/
181 static void gc_reference_unregister_intern(list_t *list, java_object_t **ref)
183 list_gcref_entry_t *re;
185 /* the global GC lock also guards the reference lists */
188 GC_LOG2( printf("Un-Registering Reference at %p\n", (void *) ref); );
190 /* search for the appropriate reference entry */
191 for (re = list_first(list); re != NULL; re = list_next(list, re)) {
192 if (re->ref == ref) {
193 /* remove the entry from the given list */
194 list_remove(list, re);
196 /* free the reference entry */
197 FREE(re, list_gcref_entry_t);
203 vm_abort("gc_reference_unregister_intern: reference not found");
205 /* the global GC lock also guards the reference lists */
209 void gc_reference_unregister(java_object_t **ref)
211 gc_reference_unregister_intern(gc_reflist_strong, ref);
214 void gc_weakreference_unregister(java_object_t **ref)
216 gc_reference_unregister_intern(gc_reflist_weak, ref);
220 /* gc_collect ******************************************************************
222 This is the main machinery which manages a collection. It should be run by
223 the thread which triggered the collection.
228 STEPS OF A COLLECTION:
231 *******************************************************************************/
233 void gc_collect(s4 level)
240 #if defined(ENABLE_RT_TIMING)
241 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
244 /* enter the global gc lock */
247 /* remember start of dump memory area */
250 GCSTAT_COUNT(gcstat_collections);
252 RT_TIMING_GET_TIME(time_start);
254 /* let everyone know we want to do a collection */
255 GC_ASSERT(!gc_pending);
258 /* finalizer is not notified, unless marking tells us to do so */
259 gc_notify_finalizer = false;
261 #if defined(ENABLE_THREADS)
262 /* stop the world here */
263 GC_LOG( dolog("GC: Suspending threads ..."); );
264 GC_LOG( threads_dump(); );
266 /*GC_LOG( threads_dump(); );*/
267 GC_LOG( dolog("GC: Suspension finished."); );
271 /* get the stacktrace of the current thread and make sure it is non-empty */
272 GC_LOG( printf("Stacktrace of current thread:\n"); );
273 st = stacktrace_get_current();
275 vm_abort("gc_collect: no stacktrace available for current thread!");
276 GC_LOG( stacktrace_print(st); );
279 /* sourcestate of the current thread, assuming we are in the native world */
280 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
281 #if defined(ENABLE_THREADS)
282 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
284 replace_gc_from_native(THREADOBJECT, NULL, NULL);
286 /* everyone is halted now, we consider ourselves running */
287 GC_ASSERT(!gc_running);
291 RT_TIMING_GET_TIME(time_suspend);
293 GC_LOG( heap_println_usage(); );
294 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
296 /* find the global and local rootsets */
297 rs = rootset_readout();
300 /* print the rootsets if debugging is enabled */
301 if (opt_GCDebugRootSet)
305 RT_TIMING_GET_TIME(time_rootset);
309 /* mark the objects considering the given rootset */
311 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
313 RT_TIMING_GET_TIME(time_mark);
315 /* compact the heap */
316 compact_me(rs, heap_region_main);
317 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
319 #if defined(ENABLE_MEMCHECK)
320 /* invalidate the rest of the main region */
321 region_invalidate(heap_region_main);
324 RT_TIMING_GET_TIME(time_compact);
326 /* check if we should increase the heap size */
327 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
328 heap_increase_size(rs);
332 /* copy the heap to new region */
334 regioninfo_t *src, *dst;
336 src = heap_region_main;
337 dst = NEW(regioninfo_t);
338 region_create(dst, heap_current_size);
339 copy_me(heap_region_main, dst, rs);
340 heap_region_main = dst;
342 /* invalidate old heap */
343 memset(src->base, 0x66, src->size);
347 /* TODO: check my return value! */
348 /*heap_increase_size();*/
350 /* write back the rootset to update root references */
351 GC_LOG( rootset_print(rs); );
352 rootset_writeback(rs);
354 #if defined(ENABLE_STATISTICS)
359 /* we are no longer running */
362 #if defined(ENABLE_THREADS)
363 /* start the world again */
364 GC_LOG( dolog("GC: Reanimating world ..."); );
365 threads_startworld();
366 /*GC_LOG( threads_dump(); );*/
369 #if defined(GCCONF_FINALIZER)
370 /* does the finalizer need to be notified */
371 if (gc_notify_finalizer)
375 RT_TIMING_GET_TIME(time_end);
377 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
378 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
379 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
380 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
381 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
382 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
384 /* free dump memory area */
387 /* leave the global gc lock */
390 /* XXX move this to an appropriate place */
391 lock_hashtable_cleanup();
395 #if defined(ENABLE_THREADS)
396 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
400 /* check if the thread suspended itself */
402 GC_LOG( dolog("GC: Suspended myself!"); );
406 /* thread was forcefully suspended */
407 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
409 /* check where this thread came to a halt */
410 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
412 if (thread->gc_critical) {
413 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
417 /* wait till this thread suspends itself */
421 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
423 /* we assume we are in a native! */
424 replace_gc_from_native(thread, pc, sp);
432 code = code_find_codeinfo_for_pc_nocheck(pc);
435 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
438 /* arm the replacement points of the code this thread is in */
439 replace_activate_replacement_points(code, false);
441 /* wait till this thread suspends itself */
445 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
447 /* re-suspend me later */
448 /* TODO: implement me! */
449 /* TODO: (this is a rare race condition which was not yet triggered) */
457 /* this point should never be reached */
464 /* gc_call *********************************************************************
466 Forces a full collection of the whole Java Heap.
467 This is the function which is called by java.lang.Runtime.gc()
469 *******************************************************************************/
474 dolog("GC: Forced Collection ...");
476 GCSTAT_COUNT(gcstat_collections_forced);
481 dolog("GC: Forced Collection finished.");
485 /* gc_invoke_finalizers ********************************************************
487 Forces invocation of all the finalizers for objects which are reclaimable.
488 This is the function which is called by the finalizer thread.
490 *******************************************************************************/
492 void gc_invoke_finalizers(void)
495 dolog("GC: Invoking finalizers ...");
500 dolog("GC: Invoking finalizers finished.");
504 /* gc_finalize_all *************************************************************
506 Forces the finalization of all objects on the Java Heap.
507 This is the function which is called by java.lang.Runtime.exit()
509 We do this by setting all objects with finalizers to reclaimable,
510 which is inherently dangerouse because objects may still be alive.
512 *******************************************************************************/
514 void gc_finalize_all(void)
517 /* doing this is deprecated, inform the user */
518 dolog("gc_finalize_all: Deprecated!");
521 /* set all objects with finalizers to reclaimable */
522 final_set_all_reclaimable();
524 /* notify the finalizer thread */
529 /* Informational getter functions *********************************************/
531 s8 gc_get_heap_size(void) { return heap_current_size; }
532 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
533 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
534 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
537 /* Statistics *****************************************************************/
539 #if defined(ENABLE_STATISTICS)
540 int gcstat_collections;
541 int gcstat_collections_forced;
542 int gcstat_mark_depth;
543 int gcstat_mark_depth_max;
544 int gcstat_mark_count;
546 void gcstat_println()
548 printf("\nGCSTAT - General Statistics:\n");
549 printf("\t# of collections: %d\n", gcstat_collections);
550 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
552 printf("\nGCSTAT - Marking Statistics:\n");
553 printf("\t# of objects marked: %d\n", gcstat_mark_count);
554 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
556 printf("\nGCSTAT - Compaction Statistics:\n");
560 #endif /* defined(ENABLE_STATISTICS) */
564 * These are local overrides for various environment variables in Emacs.
565 * Please do not remove this and leave it at the end of the file, where
566 * Emacs will automagically detect them.
567 * ---------------------------------------------------------------------
570 * indent-tabs-mode: t
574 * vim:noexpandtab:sw=4:ts=4: