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 #if defined(ENABLE_HANDLES)
85 /* check our indirection cells */
86 if (OFFSET(java_handle_t, heap_object) != 0)
87 vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
88 if (OFFSET(hashtable_classloader_entry, object) != 0)
89 vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
90 if (OFFSET(hashtable_global_ref_entry, o) != 0)
91 vm_abort("gc_init: global reference entry cannot be used as indirection cell: %d", OFFSET(hashtable_global_ref_entry, o));
97 /* set global variables */
101 /* create list for external references */
102 gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
104 #if defined(ENABLE_THREADS)
105 /* create global gc lock object */
106 gc_global_lock = NEW(java_object_t);
107 lock_init_object_lock(gc_global_lock);
110 /* region for uncollectable objects */
111 heap_region_sys = NEW(regioninfo_t);
112 if (!region_create(heap_region_sys, GC_SYS_SIZE))
113 vm_abort("gc_init: region_create failed: out of memory");
115 /* region for java objects */
116 heap_region_main = NEW(regioninfo_t);
117 if (!region_create(heap_region_main, heapstartsize))
118 vm_abort("gc_init: region_create failed: out of memory");
120 heap_current_size = heapstartsize;
121 heap_maximal_size = heapmaxsize;
125 /* gc_reference_register *******************************************************
127 Register an external reference which points onto the Heap and keeps
128 objects alive (strong reference).
130 *******************************************************************************/
132 void gc_reference_register(java_object_t **ref, int32_t reftype)
134 list_gcref_entry_t *re;
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);
140 #if defined(ENABLE_THREADS)
141 /* XXX dirty hack because threads_init() not yet called */
142 if (THREADOBJECT == NULL) {
143 GC_LOG( dolog("GC: Unable to register Reference!"); );
148 GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
150 re = NEW(list_gcref_entry_t);
154 re->reftype = reftype;
157 list_add_last(gc_reflist, re);
161 void gc_reference_unregister(java_object_t **ref)
163 vm_abort("gc_reference_unregister: IMPLEMENT ME!");
167 /* gc_collect ******************************************************************
169 This is the main machinery which manages a collection. It should be run by
170 the thread which triggered the collection.
175 STEPS OF A COLLECTION:
178 *******************************************************************************/
180 void gc_collect(s4 level)
186 stacktracebuffer *stb;
188 #if defined(ENABLE_RT_TIMING)
189 struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
192 /* enter the global gc lock */
193 LOCK_MONITOR_ENTER(gc_global_lock);
195 /* remember start of dump memory area */
196 dumpsize = dump_size();
198 GCSTAT_COUNT(gcstat_collections);
200 RT_TIMING_GET_TIME(time_start);
202 /* let everyone know we want to do a collection */
203 GC_ASSERT(!gc_pending);
206 /* finalizer is not notified, unless marking tells us to do so */
207 gc_notify_finalizer = false;
209 #if defined(ENABLE_THREADS)
210 /* stop the world here */
211 GC_LOG( dolog("GC: Suspending threads ..."); );
212 GC_LOG( threads_dump(); );
214 /*GC_LOG( threads_dump(); );*/
215 GC_LOG( dolog("GC: Suspension finished."); );
219 /* get the stacktrace of the current thread and make sure it is non-empty */
220 GC_LOG( printf("Stacktrace of current thread:\n"); );
221 sfi = STACKFRAMEINFO;
222 stb = stacktrace_create(sfi);
224 vm_abort("gc_collect: no stacktrace available for current thread!");
225 GC_LOG( stacktrace_print_trace_from_buffer(stb); );
228 /* sourcestate of the current thread, assuming we are in the native world */
229 GC_LOG( dolog("GC: Stackwalking current thread ..."); );
230 #if defined(ENABLE_THREADS)
231 GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
233 replace_gc_from_native(THREADOBJECT, NULL, NULL);
235 /* everyone is halted now, we consider ourselves running */
236 GC_ASSERT(!gc_running);
240 RT_TIMING_GET_TIME(time_suspend);
242 GC_LOG( heap_println_usage(); );
243 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
245 /* find the global and local rootsets */
246 rs = rootset_readout();
247 GC_LOG( rootset_print(rs); );
249 RT_TIMING_GET_TIME(time_rootset);
253 /* mark the objects considering the given rootset */
255 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
257 RT_TIMING_GET_TIME(time_mark);
259 /* compact the heap */
260 compact_me(rs, heap_region_main);
261 /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
263 #if defined(ENABLE_MEMCHECK)
264 /* invalidate the rest of the main region */
265 region_invalidate(heap_region_main);
268 RT_TIMING_GET_TIME(time_compact);
270 /* check if we should increase the heap size */
271 if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
272 heap_increase_size(rs);
276 /* copy the heap to new region */
278 regioninfo_t *src, *dst;
280 src = heap_region_main;
281 dst = NEW(regioninfo_t);
282 region_create(dst, heap_current_size);
283 copy_me(heap_region_main, dst, rs);
284 heap_region_main = dst;
286 /* invalidate old heap */
287 memset(src->base, 0x66, src->size);
291 /* TODO: check my return value! */
292 /*heap_increase_size();*/
294 /* write back the rootset to update root references */
295 GC_LOG( rootset_print(rs); );
296 rootset_writeback(rs);
298 #if defined(ENABLE_STATISTICS)
303 /* we are no longer running */
306 #if defined(ENABLE_THREADS)
307 /* start the world again */
308 GC_LOG( dolog("GC: Reanimating world ..."); );
309 threads_startworld();
310 /*GC_LOG( threads_dump(); );*/
313 #if defined(GCCONF_FINALIZER)
314 /* does the finalizer need to be notified */
315 if (gc_notify_finalizer)
319 RT_TIMING_GET_TIME(time_end);
321 RT_TIMING_TIME_DIFF(time_start , time_suspend, RT_TIMING_GC_SUSPEND);
322 RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
323 RT_TIMING_TIME_DIFF(time_rootset, time_mark , RT_TIMING_GC_MARK);
324 RT_TIMING_TIME_DIFF(time_mark , time_compact, RT_TIMING_GC_COMPACT);
325 RT_TIMING_TIME_DIFF(time_compact, time_end , RT_TIMING_GC_ROOTSET2);
326 RT_TIMING_TIME_DIFF(time_start , time_end , RT_TIMING_GC_TOTAL);
328 /* free dump memory area */
329 dump_release(dumpsize);
331 /* leave the global gc lock */
332 LOCK_MONITOR_EXIT(gc_global_lock);
337 #if defined(ENABLE_THREADS)
338 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
342 /* check if the thread suspended itself */
344 GC_LOG( dolog("GC: Suspended myself!"); );
348 /* thread was forcefully suspended */
349 GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
351 /* check where this thread came to a halt */
352 if (thread->flags & THREAD_FLAG_IN_NATIVE) {
354 if (thread->gc_critical) {
355 GC_LOG( dolog("\tNATIVE & CRITICAL -> retry"); );
359 /* wait till this thread suspends itself */
363 GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
365 /* we assume we are in a native! */
366 replace_gc_from_native(thread, pc, sp);
374 code = code_find_codeinfo_for_pc_nocheck(pc);
377 GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
380 /* arm the replacement points of the code this thread is in */
381 replace_activate_replacement_points(code, false);
383 /* wait till this thread suspends itself */
387 GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
389 /* re-suspend me later */
390 /* TODO: implement me! */
391 /* TODO: (this is a rare race condition which was not yet triggered) */
399 /* this point should never be reached */
406 /* gc_call *********************************************************************
408 Forces a full collection of the whole Java Heap.
409 This is the function which is called by java.lang.Runtime.gc()
411 *******************************************************************************/
416 dolog("GC: Forced Collection ...");
418 GCSTAT_COUNT(gcstat_collections_forced);
423 dolog("GC: Forced Collection finished.");
427 /* gc_invoke_finalizers ********************************************************
429 Forces invocation of all the finalizers for objects which are reclaimable.
430 This is the function which is called by the finalizer thread.
432 *******************************************************************************/
434 void gc_invoke_finalizers(void)
437 dolog("GC: Invoking finalizers ...");
442 dolog("GC: Invoking finalizers finished.");
446 /* gc_finalize_all *************************************************************
448 Forces the finalization of all objects on the Java Heap.
449 This is the function which is called by java.lang.Runtime.exit()
451 We do this by setting all objects with finalizers to reclaimable,
452 which is inherently dangerouse because objects may still be alive.
454 *******************************************************************************/
456 void gc_finalize_all(void)
459 /* doing this is deprecated, inform the user */
460 dolog("gc_finalize_all: Deprecated!");
463 /* set all objects with finalizers to reclaimable */
464 final_set_all_reclaimable();
466 /* notify the finalizer thread */
471 /* Informational getter functions *********************************************/
473 s8 gc_get_heap_size(void) { return heap_current_size; }
474 s8 gc_get_free_bytes(void) { return heap_region_main->free; }
475 s8 gc_get_total_bytes(void) { return heap_region_main->size - heap_region_main->free; }
476 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
479 /* Statistics *****************************************************************/
481 #if defined(ENABLE_STATISTICS)
482 int gcstat_collections;
483 int gcstat_collections_forced;
484 int gcstat_mark_depth;
485 int gcstat_mark_depth_max;
486 int gcstat_mark_count;
488 void gcstat_println()
490 printf("\nGCSTAT - General Statistics:\n");
491 printf("\t# of collections: %d\n", gcstat_collections);
492 printf("\t# of forced collections: %d\n", gcstat_collections_forced);
494 printf("\nGCSTAT - Marking Statistics:\n");
495 printf("\t# of objects marked: %d\n", gcstat_mark_count);
496 printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
498 printf("\nGCSTAT - Compaction Statistics:\n");
502 #endif /* defined(ENABLE_STATISTICS) */
506 * These are local overrides for various environment variables in Emacs.
507 * Please do not remove this and leave it at the end of the file, where
508 * Emacs will automagically detect them.
509 * ---------------------------------------------------------------------
512 * indent-tabs-mode: t
516 * vim:noexpandtab:sw=4:ts=4: