b54cb155e7c2bdf675e5d2f37246b1c628817343
[cacao.git] / src / mm / cacao-gc / gc.c
1 /* src/mm/cacao-gc/gc.c - main garbage collector methods
2
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
7
8    This file is part of CACAO.
9
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.
14
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.
19
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
23    02110-1301, USA.
24
25    $Id$
26
27 */
28
29
30 #include "config.h"
31 #include <signal.h>
32 #include "vm/types.h"
33
34 #include "threads/lock-common.h"
35 #include "threads/threads-common.h"
36
37 #include "compact.h"
38 #include "copy.h"
39 #include "final.h"
40 #include "gc.h"
41 #include "heap.h"
42 #include "mark.h"
43 #include "region.h"
44 #include "rootset.h"
45 #include "mm/memory.h"
46 #include "toolbox/logging.h"
47 #include "vm/finalizer.h"
48 #include "vm/vm.h"
49 #include "vmcore/rt-timing.h"
50
51
52 /* Global Variables ***********************************************************/
53
54 bool gc_pending;
55 bool gc_running;
56 bool gc_notify_finalizer;
57
58 list_t *gc_reflist;
59
60 #if defined(ENABLE_THREADS)
61 java_objectheader *gc_global_lock;
62 #endif
63
64 #if !defined(ENABLE_THREADS)
65 executionstate_t *_no_threads_executionstate;
66 sourcestate_t    *_no_threads_sourcestate;
67 #endif
68
69
70 /* gc_init *********************************************************************
71
72    Initializes the garbage collector.
73
74 *******************************************************************************/
75
76 #define GC_SYS_SIZE (20*1024*1024)
77
78 void gc_init(u4 heapmaxsize, u4 heapstartsize)
79 {
80         if (opt_verbosegc)
81                 dolog("GC: Initialising with heap-size %d (max. %d)",
82                         heapstartsize, heapmaxsize);
83
84         /* finalizer stuff */
85         final_init();
86
87         /* set global variables */
88         gc_pending = false;
89         gc_running = false;
90
91         /* create list for external references */
92         gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
93
94 #if defined(ENABLE_THREADS)
95         /* create global gc lock object */
96         gc_global_lock = NEW(java_objectheader);
97         lock_init_object_lock(gc_global_lock);
98 #endif
99
100         /* region for uncollectable objects */
101         heap_region_sys = NEW(regioninfo_t);
102         if (!region_create(heap_region_sys, GC_SYS_SIZE))
103                 vm_abort("gc_init: region_create failed: out of memory");
104
105         /* region for java objects */
106         heap_region_main = NEW(regioninfo_t);
107         if (!region_create(heap_region_main, heapstartsize))
108                 vm_abort("gc_init: region_create failed: out of memory");
109
110         heap_current_size = heapstartsize;
111         heap_maximal_size = heapmaxsize;
112 }
113
114
115 /* gc_reference_register *******************************************************
116
117    Register an external reference which points onto the Heap and keeps
118    objects alive (strong reference).
119
120 *******************************************************************************/
121
122 void gc_reference_register(java_objectheader **ref)
123 {
124         list_gcref_entry_t *re;
125
126         /* the reference needs to be registered before it is set, so make sure the
127            reference is not yet set */
128         GC_ASSERT(*ref == NULL);
129
130         /* are we called from threads_preinit? */
131         if (gc_reflist == NULL) {
132                 GC_LOG( dolog("GC: Unable to register Reference!"); );
133                 return;
134         }
135
136         GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
137
138         re = NEW(list_gcref_entry_t);
139
140         re->ref = ref;
141
142         list_add_last(gc_reflist, re);
143 }
144
145
146 /* gc_collect ******************************************************************
147
148    This is the main machinery which manages a collection. It should be run by
149    the thread which triggered the collection.
150
151    IN:
152      XXX
153
154    STEPS OF A COLLECTION:
155      XXX
156
157 *******************************************************************************/
158
159 void gc_collect(s4 level)
160 {
161         rootset_t    *rs;
162         s4            dumpsize;
163 #if !defined(NDEBUG)
164         stackframeinfo   *sfi;
165         stacktracebuffer *stb;
166 #endif
167 #if defined(ENABLE_RT_TIMING)
168         struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
169 #endif
170
171         /* enter the global gc lock */
172         LOCK_MONITOR_ENTER(gc_global_lock);
173
174         /* remember start of dump memory area */
175         dumpsize = dump_size();
176
177         GCSTAT_COUNT(gcstat_collections);
178
179         RT_TIMING_GET_TIME(time_start);
180
181         /* let everyone know we want to do a collection */
182         GC_ASSERT(!gc_pending);
183         gc_pending = true;
184
185         /* finalizer is not notified, unless marking tells us to do so */
186         gc_notify_finalizer = false;
187
188 #if defined(ENABLE_THREADS)
189         /* stop the world here */
190         GC_LOG( dolog("GC: Suspending threads ..."); );
191         GC_LOG( threads_dump(); );
192         threads_stopworld();
193         /*GC_LOG( threads_dump(); );*/
194         GC_LOG( dolog("GC: Suspension finished."); );
195 #endif
196
197 #if !defined(NDEBUG)
198         /* get the stacktrace of the current thread and make sure it is non-empty */
199         GC_LOG( printf("Stacktrace of current thread:\n"); );
200         sfi = STACKFRAMEINFO;
201         stb = stacktrace_create(sfi);
202         if (stb == NULL)
203                 vm_abort("gc_collect: no stacktrace available for current thread!");
204         GC_LOG( stacktrace_print_trace_from_buffer(stb); );
205 #endif
206
207         /* sourcestate of the current thread, assuming we are in the native world */
208         GC_LOG( dolog("GC: Stackwalking current thread ..."); );
209 #if defined(ENABLE_THREADS)
210         GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
211 #endif
212         replace_gc_from_native(THREADOBJECT, NULL, NULL);
213
214         /* everyone is halted now, we consider ourselves running */
215         GC_ASSERT(!gc_running);
216         gc_pending = false;
217         gc_running = true;
218
219         RT_TIMING_GET_TIME(time_suspend);
220
221         GC_LOG( heap_println_usage(); );
222         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
223
224         /* find the global and local rootsets */
225         rs = rootset_readout();
226         GC_LOG( rootset_print(rs); );
227
228         RT_TIMING_GET_TIME(time_rootset);
229
230 #if 1
231
232         /* mark the objects considering the given rootset */
233         mark_me(rs);
234         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
235
236         RT_TIMING_GET_TIME(time_mark);
237
238         /* compact the heap */
239         compact_me(rs, heap_region_main);
240         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
241
242 #if defined(ENABLE_MEMCHECK)
243         /* invalidate the rest of the main region */
244         region_invalidate(heap_region_main);
245 #endif
246
247         RT_TIMING_GET_TIME(time_compact);
248
249         /* check if we should increase the heap size */
250         if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
251                 heap_increase_size(rs);
252
253 #else
254
255         /* copy the heap to new region */
256         {
257                 regioninfo_t *src, *dst;
258
259                 src = heap_region_main;
260                 dst = NEW(regioninfo_t);
261                 region_create(dst, heap_current_size);
262                 copy_me(heap_region_main, dst, rs);
263                 heap_region_main = dst;
264
265                 /* invalidate old heap */
266                 memset(src->base, 0x66, src->size);
267         }
268 #endif
269
270         /* TODO: check my return value! */
271         /*heap_increase_size();*/
272
273         /* write back the rootset to update root references */
274         GC_LOG( rootset_print(rs); );
275         rootset_writeback(rs);
276
277 #if defined(ENABLE_STATISTICS)
278         if (opt_verbosegc)
279                 gcstat_println();
280 #endif
281
282         /* we are no longer running */
283         gc_running = false;
284
285 #if defined(ENABLE_THREADS)
286         /* start the world again */
287         GC_LOG( dolog("GC: Reanimating world ..."); );
288         threads_startworld();
289         /*GC_LOG( threads_dump(); );*/
290 #endif
291
292 #if defined(GCCONF_FINALIZER)
293         /* does the finalizer need to be notified */
294         if (gc_notify_finalizer)
295                 finalizer_notify();
296 #endif
297
298         RT_TIMING_GET_TIME(time_end);
299
300         RT_TIMING_TIME_DIFF(time_start  , time_suspend, RT_TIMING_GC_SUSPEND);
301         RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
302         RT_TIMING_TIME_DIFF(time_rootset, time_mark   , RT_TIMING_GC_MARK);
303         RT_TIMING_TIME_DIFF(time_mark   , time_compact, RT_TIMING_GC_COMPACT);
304         RT_TIMING_TIME_DIFF(time_compact, time_end    , RT_TIMING_GC_ROOTSET2);
305         RT_TIMING_TIME_DIFF(time_start  , time_end    , RT_TIMING_GC_TOTAL);
306
307     /* free dump memory area */
308     dump_release(dumpsize);
309
310         /* leave the global gc lock */
311         LOCK_MONITOR_EXIT(gc_global_lock);
312
313 }
314
315
316 #if defined(ENABLE_THREADS)
317 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
318 {
319         codeinfo         *code;
320
321         /* check if the thread suspended itself */
322         if (pc == NULL) {
323                 GC_LOG( dolog("GC: Suspended myself!"); );
324                 return true;
325         }
326
327         /* thread was forcefully suspended */
328         GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
329
330         /* check where this thread came to a halt */
331         if (thread->flags & THREAD_FLAG_IN_NATIVE) {
332
333                 if (thread->gc_critical) {
334                         GC_LOG( dolog("\tNATIVE &  CRITICAL -> retry"); );
335
336                         GC_ASSERT(0);
337
338                         /* wait till this thread suspends itself */
339                         return false;
340
341                 } else {
342                         GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
343
344                         /* we assume we are in a native! */
345                         replace_gc_from_native(thread, pc, sp);
346
347                         /* suspend me now */
348                         return true;
349
350                 }
351
352         } else {
353                 code = code_find_codeinfo_for_pc_nocheck(pc);
354
355                 if (code != NULL) {
356                         GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
357                                         pc, code); );
358
359                         /* arm the replacement points of the code this thread is in */
360                         replace_activate_replacement_points(code, false);
361
362                         /* wait till this thread suspends itself */
363                         return false;
364
365                 } else {
366                         GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
367
368                         /* re-suspend me later */
369                         /* TODO: implement me! */
370                         /* TODO: (this is a rare race condition which was not yet triggered) */
371                         GC_ASSERT(0);
372                         return false;
373
374                 }
375
376         }
377
378         /* this point should never be reached */
379         GC_ASSERT(0);
380
381 }
382 #endif
383
384
385 /* gc_call *********************************************************************
386
387    Forces a full collection of the whole Java Heap.
388    This is the function which is called by java.lang.Runtime.gc()
389
390 *******************************************************************************/
391
392 void gc_call(void)
393 {
394         if (opt_verbosegc)
395                 dolog("GC: Forced Collection ...");
396
397         GCSTAT_COUNT(gcstat_collections_forced);
398
399         gc_collect(0);
400
401         if (opt_verbosegc)
402                 dolog("GC: Forced Collection finished.");
403 }
404
405
406 /* gc_invoke_finalizers ********************************************************
407
408    Forces invocation of all the finalizers for objects which are reclaimable.
409    This is the function which is called by the finalizer thread.
410
411 *******************************************************************************/
412
413 void gc_invoke_finalizers(void)
414 {
415         if (opt_verbosegc)
416                 dolog("GC: Invoking finalizers ...");
417
418         final_invoke();
419
420         if (opt_verbosegc)
421                 dolog("GC: Invoking finalizers finished.");
422 }
423
424
425 /* gc_finalize_all *************************************************************
426
427    Forces the finalization of all objects on the Java Heap.
428    This is the function which is called by java.lang.Runtime.exit()
429
430    We do this by setting all objects with finalizers to reclaimable,
431    which is inherently dangerouse because objects may still be alive.
432
433 *******************************************************************************/
434
435 void gc_finalize_all(void)
436 {
437 #if !defined(NDEBUG)
438         /* doing this is deprecated, inform the user */
439         dolog("gc_finalize_all: Deprecated!");
440 #endif
441
442         /* set all objects with finalizers to reclaimable */
443         final_set_all_reclaimable();
444
445         /* notify the finalizer thread */
446         finalizer_notify();
447 }
448
449
450 /* Informational getter functions *********************************************/
451
452 s8 gc_get_heap_size(void)     { return heap_current_size; }
453 s8 gc_get_free_bytes(void)    { return heap_region_main->free; }
454 s8 gc_get_total_bytes(void)   { return heap_region_main->size - heap_region_main->free; }
455 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
456
457
458 /* Statistics *****************************************************************/
459
460 #if defined(ENABLE_STATISTICS)
461 int gcstat_collections;
462 int gcstat_collections_forced;
463 int gcstat_mark_depth;
464 int gcstat_mark_depth_max;
465 int gcstat_mark_count;
466
467 void gcstat_println()
468 {
469         printf("\nGCSTAT - General Statistics:\n");
470         printf("\t# of collections: %d\n", gcstat_collections);
471         printf("\t# of forced collections: %d\n", gcstat_collections_forced);
472
473     printf("\nGCSTAT - Marking Statistics:\n");
474     printf("\t# of objects marked: %d\n", gcstat_mark_count);
475     printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
476
477         printf("\nGCSTAT - Compaction Statistics:\n");
478
479         printf("\n");
480 }
481 #endif /* defined(ENABLE_STATISTICS) */
482
483
484 /*
485  * These are local overrides for various environment variables in Emacs.
486  * Please do not remove this and leave it at the end of the file, where
487  * Emacs will automagically detect them.
488  * ---------------------------------------------------------------------
489  * Local variables:
490  * mode: c
491  * indent-tabs-mode: t
492  * c-basic-offset: 4
493  * tab-width: 4
494  * End:
495  * vim:noexpandtab:sw=4:ts=4:
496  */