1 /* src/mm/cacao-gc/gc.c - main garbage collector methods
3 Copyright (C) 2006, 2007, 2008
4 CACAOVM - Verein zu Foerderung der freien virtuellen Machine 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/threads-common.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_unsynced(list); re != NULL; re = list_next_unsynced(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_unsynced(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_unsynced(list); re != NULL; re = list_next_unsynced(list, re)) {
191 if (re->ref == ref) {
192 /* remove the entry from the given list */
193 list_remove_unsynced(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)
237 stackframeinfo_t *sfi;
238 stacktracebuffer *stb;
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 sfi = STACKFRAMEINFO;
274 stb = stacktrace_create(sfi);
276 vm_abort("gc_collect: no stacktrace available for current thread!");
277 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
280 /* sourcestate of the current thread, assuming we are in the native world */
281 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
282 #if defined(ENABLE_THREADS)
283 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
285 replace_gc_from_native(THREADOBJECT, NULL, NULL);
287 /* everyone is halted now, we consider ourselves running */
288 GC_ASSERT(!gc_running);
292 RT_TIMING_GET_TIME(time_suspend);
294 GC_LOG( heap_println_usage(); );
295 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
297 /* find the global and local rootsets */
298 rs = rootset_readout();
301 /* print the rootsets if debugging is enabled */
302 if (opt_GCDebugRootSet)
306 RT_TIMING_GET_TIME(time_rootset);
310 /* mark the objects considering the given rootset */
312 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
314 RT_TIMING_GET_TIME(time_mark);
316 /* compact the heap */
317 compact_me(rs, heap_region_main);
318 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
320 #if defined(ENABLE_MEMCHECK)
321 /* invalidate the rest of the main region */
322 region_invalidate(heap_region_main);
325 RT_TIMING_GET_TIME(time_compact);
327 /* check if we should increase the heap size */
328 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
329 heap_increase_size(rs);
333 /* copy the heap to new region */
335 regioninfo_t *src, *dst;
337 src = heap_region_main;
338 dst = NEW(regioninfo_t);
339 region_create(dst, heap_current_size);
340 copy_me(heap_region_main, dst, rs);
341 heap_region_main = dst;
343 /* invalidate old heap */
344 memset(src->base, 0x66, src->size);
348 /* TODO: check my return value! */
349 /*heap_increase_size();*/
351 /* write back the rootset to update root references */
352 GC_LOG( rootset_print(rs); );
353 rootset_writeback(rs);
355 #if defined(ENABLE_STATISTICS)
360 /* we are no longer running */
363 #if defined(ENABLE_THREADS)
364 /* start the world again */
365 GC_LOG( dolog("GC: Reanimating world ..."); );
366 threads_startworld();
367 /*GC_LOG( threads_dump(); );*/
370 #if defined(GCCONF_FINALIZER)
371 /* does the finalizer need to be notified */
372 if (gc_notify_finalizer)
376 RT_TIMING_GET_TIME(time_end);
378 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
379 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
380 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
381 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
382 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
383 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
385 /* free dump memory area */
388 /* leave the global gc lock */
391 /* XXX move this to an appropriate place */
392 lock_hashtable_cleanup();
396 #if defined(ENABLE_THREADS)
397 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
401 /* check if the thread suspended itself */
403 GC_LOG( dolog("GC: Suspended myself!"); );
407 /* thread was forcefully suspended */
408 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
410 /* check where this thread came to a halt */
411 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
413 if (thread->gc_critical) {
414 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
418 /* wait till this thread suspends itself */
422 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
424 /* we assume we are in a native! */
425 replace_gc_from_native(thread, pc, sp);
433 code = code_find_codeinfo_for_pc_nocheck(pc);
436 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
439 /* arm the replacement points of the code this thread is in */
440 replace_activate_replacement_points(code, false);
442 /* wait till this thread suspends itself */
446 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
448 /* re-suspend me later */
449 /* TODO: implement me! */
450 /* TODO: (this is a rare race condition which was not yet triggered) */
458 /* this point should never be reached */
465 /* gc_call *********************************************************************
467 Forces a full collection of the whole Java Heap.
468 This is the function which is called by java.lang.Runtime.gc()
470 *******************************************************************************/
475 dolog("GC: Forced Collection ...");
477 GCSTAT_COUNT(gcstat_collections_forced);
482 dolog("GC: Forced Collection finished.");
486 /* gc_invoke_finalizers ********************************************************
488 Forces invocation of all the finalizers for objects which are reclaimable.
489 This is the function which is called by the finalizer thread.
491 *******************************************************************************/
493 void gc_invoke_finalizers(void)
496 dolog("GC: Invoking finalizers ...");
501 dolog("GC: Invoking finalizers finished.");
505 /* gc_finalize_all *************************************************************
507 Forces the finalization of all objects on the Java Heap.
508 This is the function which is called by java.lang.Runtime.exit()
510 We do this by setting all objects with finalizers to reclaimable,
511 which is inherently dangerouse because objects may still be alive.
513 *******************************************************************************/
515 void gc_finalize_all(void)
518 /* doing this is deprecated, inform the user */
519 dolog("gc_finalize_all: Deprecated!");
522 /* set all objects with finalizers to reclaimable */
523 final_set_all_reclaimable();
525 /* notify the finalizer thread */
530 /* Informational getter functions *********************************************/
532 s8 gc_get_heap_size(void) { return heap_current_size; }
533 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
534 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
535 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
538 /* Statistics *****************************************************************/
540 #if defined(ENABLE_STATISTICS)
541 int gcstat_collections;
542 int gcstat_collections_forced;
543 int gcstat_mark_depth;
544 int gcstat_mark_depth_max;
545 int gcstat_mark_count;
547 void gcstat_println()
549 printf("\nGCSTAT - General Statistics:\n");
550 printf("\t# of collections: %d\n", gcstat_collections);
551 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
553 printf("\nGCSTAT - Marking Statistics:\n");
554 printf("\t# of objects marked: %d\n", gcstat_mark_count);
555 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
557 printf("\nGCSTAT - Compaction Statistics:\n");
561 #endif /* defined(ENABLE_STATISTICS) */
565 * These are local overrides for various environment variables in Emacs.
566 * Please do not remove this and leave it at the end of the file, where
567 * Emacs will automagically detect them.
568 * ---------------------------------------------------------------------
571 * indent-tabs-mode: t
575 * vim:noexpandtab:sw=4:ts=4: