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;
58 #if defined(ENABLE_THREADS)
59 java_object_t *gc_global_lock;
62 #if !defined(ENABLE_THREADS)
63 executionstate_t *_no_threads_executionstate;
64 sourcestate_t *_no_threads_sourcestate;
68 /* gc_init *********************************************************************
70 Initializes the garbage collector.
72 *******************************************************************************/
74 #define GC_SYS_SIZE (20*1024*1024)
76 void gc_init(u4 heapmaxsize, u4 heapstartsize)
79 dolog("GC: Initialising with heap-size %d (max. %d)",
80 heapstartsize, heapmaxsize);
82 #if defined(ENABLE_HANDLES)
83 /* check our indirection cells */
84 if (OFFSET(java_handle_t, heap_object) != 0)
85 vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
86 if (OFFSET(hashtable_classloader_entry, object) != 0)
87 vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
88 if (OFFSET(hashtable_global_ref_entry, o) != 0)
89 vm_abort("gc_init: global reference entry cannot be used as indirection cell: %d", OFFSET(hashtable_global_ref_entry, o));
95 /* set global variables */
99 /* create list for external references */
100 gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
102 #if defined(ENABLE_THREADS)
103 /* create global gc lock object */
104 gc_global_lock = NEW(java_object_t);
105 lock_init_object_lock(gc_global_lock);
108 /* region for uncollectable objects */
109 heap_region_sys = NEW(regioninfo_t);
110 if (!region_create(heap_region_sys, GC_SYS_SIZE))
111 vm_abort("gc_init: region_create failed: out of memory");
113 /* region for java objects */
114 heap_region_main = NEW(regioninfo_t);
115 if (!region_create(heap_region_main, heapstartsize))
116 vm_abort("gc_init: region_create failed: out of memory");
118 heap_current_size = heapstartsize;
119 heap_maximal_size = heapmaxsize;
123 /* gc_reference_register *******************************************************
125 Register an external reference which points onto the Heap and keeps
126 objects alive (strong reference).
128 *******************************************************************************/
130 void gc_reference_register(java_object_t **ref, int32_t reftype)
132 list_gcref_entry_t *re;
134 /* the reference needs to be registered before it is set, so make sure the
135 reference is not yet set */
136 GC_ASSERT(*ref == NULL);
138 #if defined(ENABLE_THREADS)
139 /* XXX dirty hack because threads_init() not yet called */
140 if (THREADOBJECT == NULL) {
141 GC_LOG( dolog("GC: Unable to register Reference!"); );
146 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
148 re = NEW(list_gcref_entry_t);
152 re->reftype = reftype;
155 list_add_last(gc_reflist, re);
159 void gc_reference_unregister(java_object_t **ref)
161 vm_abort("gc_reference_unregister: IMPLEMENT ME!");
165 /* gc_collect ******************************************************************
167 This is the main machinery which manages a collection. It should be run by
168 the thread which triggered the collection.
173 STEPS OF A COLLECTION:
176 *******************************************************************************/
178 void gc_collect(s4 level)
184 stacktracebuffer *stb;
186 #if defined(ENABLE_RT_TIMING)
187 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
190 /* enter the global gc lock */
191 LOCK_MONITOR_ENTER(gc_global_lock);
193 /* remember start of dump memory area */
194 dumpsize = dump_size();
196 GCSTAT_COUNT(gcstat_collections);
198 RT_TIMING_GET_TIME(time_start);
200 /* let everyone know we want to do a collection */
201 GC_ASSERT(!gc_pending);
204 /* finalizer is not notified, unless marking tells us to do so */
205 gc_notify_finalizer = false;
207 #if defined(ENABLE_THREADS)
208 /* stop the world here */
209 GC_LOG( dolog("GC: Suspending threads ..."); );
210 GC_LOG( threads_dump(); );
212 /*GC_LOG( threads_dump(); );*/
213 GC_LOG( dolog("GC: Suspension finished."); );
217 /* get the stacktrace of the current thread and make sure it is non-empty */
218 GC_LOG( printf("Stacktrace of current thread:\n"); );
219 sfi = STACKFRAMEINFO;
220 stb = stacktrace_create(sfi);
222 vm_abort("gc_collect: no stacktrace available for current thread!");
223 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
226 /* sourcestate of the current thread, assuming we are in the native world */
227 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
228 #if defined(ENABLE_THREADS)
229 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
231 replace_gc_from_native(THREADOBJECT, NULL, NULL);
233 /* everyone is halted now, we consider ourselves running */
234 GC_ASSERT(!gc_running);
238 RT_TIMING_GET_TIME(time_suspend);
240 GC_LOG( heap_println_usage(); );
241 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
243 /* find the global and local rootsets */
244 rs = rootset_readout();
245 GC_LOG( rootset_print(rs); );
247 RT_TIMING_GET_TIME(time_rootset);
251 /* mark the objects considering the given rootset */
253 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
255 RT_TIMING_GET_TIME(time_mark);
257 /* compact the heap */
258 compact_me(rs, heap_region_main);
259 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
261 #if defined(ENABLE_MEMCHECK)
262 /* invalidate the rest of the main region */
263 region_invalidate(heap_region_main);
266 RT_TIMING_GET_TIME(time_compact);
268 /* check if we should increase the heap size */
269 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
270 heap_increase_size(rs);
274 /* copy the heap to new region */
276 regioninfo_t *src, *dst;
278 src = heap_region_main;
279 dst = NEW(regioninfo_t);
280 region_create(dst, heap_current_size);
281 copy_me(heap_region_main, dst, rs);
282 heap_region_main = dst;
284 /* invalidate old heap */
285 memset(src->base, 0x66, src->size);
289 /* TODO: check my return value! */
290 /*heap_increase_size();*/
292 /* write back the rootset to update root references */
293 GC_LOG( rootset_print(rs); );
294 rootset_writeback(rs);
296 #if defined(ENABLE_STATISTICS)
301 /* we are no longer running */
304 #if defined(ENABLE_THREADS)
305 /* start the world again */
306 GC_LOG( dolog("GC: Reanimating world ..."); );
307 threads_startworld();
308 /*GC_LOG( threads_dump(); );*/
311 #if defined(GCCONF_FINALIZER)
312 /* does the finalizer need to be notified */
313 if (gc_notify_finalizer)
317 RT_TIMING_GET_TIME(time_end);
319 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
320 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
321 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
322 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
323 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
324 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
326 /* free dump memory area */
327 dump_release(dumpsize);
329 /* leave the global gc lock */
330 LOCK_MONITOR_EXIT(gc_global_lock);
335 #if defined(ENABLE_THREADS)
336 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
340 /* check if the thread suspended itself */
342 GC_LOG( dolog("GC: Suspended myself!"); );
346 /* thread was forcefully suspended */
347 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
349 /* check where this thread came to a halt */
350 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
352 if (thread->gc_critical) {
353 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
357 /* wait till this thread suspends itself */
361 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
363 /* we assume we are in a native! */
364 replace_gc_from_native(thread, pc, sp);
372 code = code_find_codeinfo_for_pc_nocheck(pc);
375 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
378 /* arm the replacement points of the code this thread is in */
379 replace_activate_replacement_points(code, false);
381 /* wait till this thread suspends itself */
385 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
387 /* re-suspend me later */
388 /* TODO: implement me! */
389 /* TODO: (this is a rare race condition which was not yet triggered) */
397 /* this point should never be reached */
404 /* gc_call *********************************************************************
406 Forces a full collection of the whole Java Heap.
407 This is the function which is called by java.lang.Runtime.gc()
409 *******************************************************************************/
414 dolog("GC: Forced Collection ...");
416 GCSTAT_COUNT(gcstat_collections_forced);
421 dolog("GC: Forced Collection finished.");
425 /* gc_invoke_finalizers ********************************************************
427 Forces invocation of all the finalizers for objects which are reclaimable.
428 This is the function which is called by the finalizer thread.
430 *******************************************************************************/
432 void gc_invoke_finalizers(void)
435 dolog("GC: Invoking finalizers ...");
440 dolog("GC: Invoking finalizers finished.");
444 /* gc_finalize_all *************************************************************
446 Forces the finalization of all objects on the Java Heap.
447 This is the function which is called by java.lang.Runtime.exit()
449 We do this by setting all objects with finalizers to reclaimable,
450 which is inherently dangerouse because objects may still be alive.
452 *******************************************************************************/
454 void gc_finalize_all(void)
457 /* doing this is deprecated, inform the user */
458 dolog("gc_finalize_all: Deprecated!");
461 /* set all objects with finalizers to reclaimable */
462 final_set_all_reclaimable();
464 /* notify the finalizer thread */
469 /* Informational getter functions *********************************************/
471 s8 gc_get_heap_size(void) { return heap_current_size; }
472 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
473 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
474 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
477 /* Statistics *****************************************************************/
479 #if defined(ENABLE_STATISTICS)
480 int gcstat_collections;
481 int gcstat_collections_forced;
482 int gcstat_mark_depth;
483 int gcstat_mark_depth_max;
484 int gcstat_mark_count;
486 void gcstat_println()
488 printf("\nGCSTAT - General Statistics:\n");
489 printf("\t# of collections: %d\n", gcstat_collections);
490 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
492 printf("\nGCSTAT - Marking Statistics:\n");
493 printf("\t# of objects marked: %d\n", gcstat_mark_count);
494 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
496 printf("\nGCSTAT - Compaction Statistics:\n");
500 #endif /* defined(ENABLE_STATISTICS) */
504 * These are local overrides for various environment variables in Emacs.
505 * Please do not remove this and leave it at the end of the file, where
506 * Emacs will automagically detect them.
507 * ---------------------------------------------------------------------
510 * indent-tabs-mode: t
514 * vim:noexpandtab:sw=4:ts=4: