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 /* 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));
93 /* set global variables */
97 /* create list for external references */
98 gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
100 #if defined(ENABLE_THREADS)
101 /* create global gc lock object */
102 gc_global_lock = NEW(java_object_t);
103 lock_init_object_lock(gc_global_lock);
106 /* region for uncollectable objects */
107 heap_region_sys = NEW(regioninfo_t);
108 if (!region_create(heap_region_sys, GC_SYS_SIZE))
109 vm_abort("gc_init: region_create failed: out of memory");
111 /* region for java objects */
112 heap_region_main = NEW(regioninfo_t);
113 if (!region_create(heap_region_main, heapstartsize))
114 vm_abort("gc_init: region_create failed: out of memory");
116 heap_current_size = heapstartsize;
117 heap_maximal_size = heapmaxsize;
121 /* gc_reference_register *******************************************************
123 Register an external reference which points onto the Heap and keeps
124 objects alive (strong reference).
126 *******************************************************************************/
128 void gc_reference_register(java_object_t **ref)
130 list_gcref_entry_t *re;
132 /* the reference needs to be registered before it is set, so make sure the
133 reference is not yet set */
134 GC_ASSERT(*ref == NULL);
136 #if defined(ENABLE_THREADS)
137 /* XXX dirty hack because threads_init() not yet called */
138 if (THREADOBJECT == NULL) {
139 GC_LOG( dolog("GC: Unable to register Reference!"); );
144 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
146 re = NEW(list_gcref_entry_t);
150 list_add_last(gc_reflist, re);
154 void gc_reference_unregister(java_object_t **ref)
156 vm_abort("gc_reference_unregister: IMPLEMENT ME!");
160 /* gc_collect ******************************************************************
162 This is the main machinery which manages a collection. It should be run by
163 the thread which triggered the collection.
168 STEPS OF A COLLECTION:
171 *******************************************************************************/
173 void gc_collect(s4 level)
179 stacktracebuffer *stb;
181 #if defined(ENABLE_RT_TIMING)
182 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
185 /* enter the global gc lock */
186 LOCK_MONITOR_ENTER(gc_global_lock);
188 /* remember start of dump memory area */
189 dumpsize = dump_size();
191 GCSTAT_COUNT(gcstat_collections);
193 RT_TIMING_GET_TIME(time_start);
195 /* let everyone know we want to do a collection */
196 GC_ASSERT(!gc_pending);
199 /* finalizer is not notified, unless marking tells us to do so */
200 gc_notify_finalizer = false;
202 #if defined(ENABLE_THREADS)
203 /* stop the world here */
204 GC_LOG( dolog("GC: Suspending threads ..."); );
205 GC_LOG( threads_dump(); );
207 /*GC_LOG( threads_dump(); );*/
208 GC_LOG( dolog("GC: Suspension finished."); );
212 /* get the stacktrace of the current thread and make sure it is non-empty */
213 GC_LOG( printf("Stacktrace of current thread:\n"); );
214 sfi = STACKFRAMEINFO;
215 stb = stacktrace_create(sfi);
217 vm_abort("gc_collect: no stacktrace available for current thread!");
218 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
221 /* sourcestate of the current thread, assuming we are in the native world */
222 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
223 #if defined(ENABLE_THREADS)
224 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
226 replace_gc_from_native(THREADOBJECT, NULL, NULL);
228 /* everyone is halted now, we consider ourselves running */
229 GC_ASSERT(!gc_running);
233 RT_TIMING_GET_TIME(time_suspend);
235 GC_LOG( heap_println_usage(); );
236 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
238 /* find the global and local rootsets */
239 rs = rootset_readout();
240 GC_LOG( rootset_print(rs); );
242 RT_TIMING_GET_TIME(time_rootset);
246 /* mark the objects considering the given rootset */
248 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
250 RT_TIMING_GET_TIME(time_mark);
252 /* compact the heap */
253 compact_me(rs, heap_region_main);
254 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
256 #if defined(ENABLE_MEMCHECK)
257 /* invalidate the rest of the main region */
258 region_invalidate(heap_region_main);
261 RT_TIMING_GET_TIME(time_compact);
263 /* check if we should increase the heap size */
264 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
265 heap_increase_size(rs);
269 /* copy the heap to new region */
271 regioninfo_t *src, *dst;
273 src = heap_region_main;
274 dst = NEW(regioninfo_t);
275 region_create(dst, heap_current_size);
276 copy_me(heap_region_main, dst, rs);
277 heap_region_main = dst;
279 /* invalidate old heap */
280 memset(src->base, 0x66, src->size);
284 /* TODO: check my return value! */
285 /*heap_increase_size();*/
287 /* write back the rootset to update root references */
288 GC_LOG( rootset_print(rs); );
289 rootset_writeback(rs);
291 #if defined(ENABLE_STATISTICS)
296 /* we are no longer running */
299 #if defined(ENABLE_THREADS)
300 /* start the world again */
301 GC_LOG( dolog("GC: Reanimating world ..."); );
302 threads_startworld();
303 /*GC_LOG( threads_dump(); );*/
306 #if defined(GCCONF_FINALIZER)
307 /* does the finalizer need to be notified */
308 if (gc_notify_finalizer)
312 RT_TIMING_GET_TIME(time_end);
314 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
315 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
316 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
317 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
318 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
319 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
321 /* free dump memory area */
322 dump_release(dumpsize);
324 /* leave the global gc lock */
325 LOCK_MONITOR_EXIT(gc_global_lock);
330 #if defined(ENABLE_THREADS)
331 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
335 /* check if the thread suspended itself */
337 GC_LOG( dolog("GC: Suspended myself!"); );
341 /* thread was forcefully suspended */
342 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
344 /* check where this thread came to a halt */
345 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
347 if (thread->gc_critical) {
348 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
352 /* wait till this thread suspends itself */
356 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
358 /* we assume we are in a native! */
359 replace_gc_from_native(thread, pc, sp);
367 code = code_find_codeinfo_for_pc_nocheck(pc);
370 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
373 /* arm the replacement points of the code this thread is in */
374 replace_activate_replacement_points(code, false);
376 /* wait till this thread suspends itself */
380 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
382 /* re-suspend me later */
383 /* TODO: implement me! */
384 /* TODO: (this is a rare race condition which was not yet triggered) */
392 /* this point should never be reached */
399 /* gc_call *********************************************************************
401 Forces a full collection of the whole Java Heap.
402 This is the function which is called by java.lang.Runtime.gc()
404 *******************************************************************************/
409 dolog("GC: Forced Collection ...");
411 GCSTAT_COUNT(gcstat_collections_forced);
416 dolog("GC: Forced Collection finished.");
420 /* gc_invoke_finalizers ********************************************************
422 Forces invocation of all the finalizers for objects which are reclaimable.
423 This is the function which is called by the finalizer thread.
425 *******************************************************************************/
427 void gc_invoke_finalizers(void)
430 dolog("GC: Invoking finalizers ...");
435 dolog("GC: Invoking finalizers finished.");
439 /* gc_finalize_all *************************************************************
441 Forces the finalization of all objects on the Java Heap.
442 This is the function which is called by java.lang.Runtime.exit()
444 We do this by setting all objects with finalizers to reclaimable,
445 which is inherently dangerouse because objects may still be alive.
447 *******************************************************************************/
449 void gc_finalize_all(void)
452 /* doing this is deprecated, inform the user */
453 dolog("gc_finalize_all: Deprecated!");
456 /* set all objects with finalizers to reclaimable */
457 final_set_all_reclaimable();
459 /* notify the finalizer thread */
464 /* Informational getter functions *********************************************/
466 s8 gc_get_heap_size(void) { return heap_current_size; }
467 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
468 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
469 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
472 /* Statistics *****************************************************************/
474 #if defined(ENABLE_STATISTICS)
475 int gcstat_collections;
476 int gcstat_collections_forced;
477 int gcstat_mark_depth;
478 int gcstat_mark_depth_max;
479 int gcstat_mark_count;
481 void gcstat_println()
483 printf("\nGCSTAT - General Statistics:\n");
484 printf("\t# of collections: %d\n", gcstat_collections);
485 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
487 printf("\nGCSTAT - Marking Statistics:\n");
488 printf("\t# of objects marked: %d\n", gcstat_mark_count);
489 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
491 printf("\nGCSTAT - Compaction Statistics:\n");
495 #endif /* defined(ENABLE_STATISTICS) */
499 * These are local overrides for various environment variables in Emacs.
500 * Please do not remove this and leave it at the end of the file, where
501 * Emacs will automagically detect them.
502 * ---------------------------------------------------------------------
505 * indent-tabs-mode: t
509 * vim:noexpandtab:sw=4:ts=4: