67ff136a29872fe2ee4d142cc728cd545a6c08e2
[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_object_t *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         /* 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));
89
90         /* finalizer stuff */
91         final_init();
92
93         /* set global variables */
94         gc_pending = false;
95         gc_running = false;
96
97         /* create list for external references */
98         gc_reflist = list_create(OFFSET(list_gcref_entry_t, linkage));
99
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);
104 #endif
105
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");
110
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");
115
116         heap_current_size = heapstartsize;
117         heap_maximal_size = heapmaxsize;
118 }
119
120
121 /* gc_reference_register *******************************************************
122
123    Register an external reference which points onto the Heap and keeps
124    objects alive (strong reference).
125
126 *******************************************************************************/
127
128 void gc_reference_register(java_object_t **ref)
129 {
130         list_gcref_entry_t *re;
131
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);
135
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!"); );
140                 return;
141         }
142 #endif
143
144         GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
145
146         re = NEW(list_gcref_entry_t);
147
148         re->ref = ref;
149
150         list_add_last(gc_reflist, re);
151 }
152
153
154 void gc_reference_unregister(java_object_t **ref)
155 {
156         vm_abort("gc_reference_unregister: IMPLEMENT ME!");
157 }
158
159
160 /* gc_collect ******************************************************************
161
162    This is the main machinery which manages a collection. It should be run by
163    the thread which triggered the collection.
164
165    IN:
166      XXX
167
168    STEPS OF A COLLECTION:
169      XXX
170
171 *******************************************************************************/
172
173 void gc_collect(s4 level)
174 {
175         rootset_t    *rs;
176         s4            dumpsize;
177 #if !defined(NDEBUG)
178         stackframeinfo   *sfi;
179         stacktracebuffer *stb;
180 #endif
181 #if defined(ENABLE_RT_TIMING)
182         struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
183 #endif
184
185         /* enter the global gc lock */
186         LOCK_MONITOR_ENTER(gc_global_lock);
187
188         /* remember start of dump memory area */
189         dumpsize = dump_size();
190
191         GCSTAT_COUNT(gcstat_collections);
192
193         RT_TIMING_GET_TIME(time_start);
194
195         /* let everyone know we want to do a collection */
196         GC_ASSERT(!gc_pending);
197         gc_pending = true;
198
199         /* finalizer is not notified, unless marking tells us to do so */
200         gc_notify_finalizer = false;
201
202 #if defined(ENABLE_THREADS)
203         /* stop the world here */
204         GC_LOG( dolog("GC: Suspending threads ..."); );
205         GC_LOG( threads_dump(); );
206         threads_stopworld();
207         /*GC_LOG( threads_dump(); );*/
208         GC_LOG( dolog("GC: Suspension finished."); );
209 #endif
210
211 #if !defined(NDEBUG)
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);
216         if (stb == NULL)
217                 vm_abort("gc_collect: no stacktrace available for current thread!");
218         GC_LOG( stacktrace_print_trace_from_buffer(stb); );
219 #endif
220
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);
225 #endif
226         replace_gc_from_native(THREADOBJECT, NULL, NULL);
227
228         /* everyone is halted now, we consider ourselves running */
229         GC_ASSERT(!gc_running);
230         gc_pending = false;
231         gc_running = true;
232
233         RT_TIMING_GET_TIME(time_suspend);
234
235         GC_LOG( heap_println_usage(); );
236         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
237
238         /* find the global and local rootsets */
239         rs = rootset_readout();
240         GC_LOG( rootset_print(rs); );
241
242         RT_TIMING_GET_TIME(time_rootset);
243
244 #if 1
245
246         /* mark the objects considering the given rootset */
247         mark_me(rs);
248         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
249
250         RT_TIMING_GET_TIME(time_mark);
251
252         /* compact the heap */
253         compact_me(rs, heap_region_main);
254         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
255
256 #if defined(ENABLE_MEMCHECK)
257         /* invalidate the rest of the main region */
258         region_invalidate(heap_region_main);
259 #endif
260
261         RT_TIMING_GET_TIME(time_compact);
262
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);
266
267 #else
268
269         /* copy the heap to new region */
270         {
271                 regioninfo_t *src, *dst;
272
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;
278
279                 /* invalidate old heap */
280                 memset(src->base, 0x66, src->size);
281         }
282 #endif
283
284         /* TODO: check my return value! */
285         /*heap_increase_size();*/
286
287         /* write back the rootset to update root references */
288         GC_LOG( rootset_print(rs); );
289         rootset_writeback(rs);
290
291 #if defined(ENABLE_STATISTICS)
292         if (opt_verbosegc)
293                 gcstat_println();
294 #endif
295
296         /* we are no longer running */
297         gc_running = false;
298
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(); );*/
304 #endif
305
306 #if defined(GCCONF_FINALIZER)
307         /* does the finalizer need to be notified */
308         if (gc_notify_finalizer)
309                 finalizer_notify();
310 #endif
311
312         RT_TIMING_GET_TIME(time_end);
313
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);
320
321     /* free dump memory area */
322     dump_release(dumpsize);
323
324         /* leave the global gc lock */
325         LOCK_MONITOR_EXIT(gc_global_lock);
326
327 }
328
329
330 #if defined(ENABLE_THREADS)
331 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
332 {
333         codeinfo         *code;
334
335         /* check if the thread suspended itself */
336         if (pc == NULL) {
337                 GC_LOG( dolog("GC: Suspended myself!"); );
338                 return true;
339         }
340
341         /* thread was forcefully suspended */
342         GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
343
344         /* check where this thread came to a halt */
345         if (thread->flags & THREAD_FLAG_IN_NATIVE) {
346
347                 if (thread->gc_critical) {
348                         GC_LOG( dolog("\tNATIVE &  CRITICAL -> retry"); );
349
350                         GC_ASSERT(0);
351
352                         /* wait till this thread suspends itself */
353                         return false;
354
355                 } else {
356                         GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
357
358                         /* we assume we are in a native! */
359                         replace_gc_from_native(thread, pc, sp);
360
361                         /* suspend me now */
362                         return true;
363
364                 }
365
366         } else {
367                 code = code_find_codeinfo_for_pc_nocheck(pc);
368
369                 if (code != NULL) {
370                         GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
371                                         pc, code); );
372
373                         /* arm the replacement points of the code this thread is in */
374                         replace_activate_replacement_points(code, false);
375
376                         /* wait till this thread suspends itself */
377                         return false;
378
379                 } else {
380                         GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
381
382                         /* re-suspend me later */
383                         /* TODO: implement me! */
384                         /* TODO: (this is a rare race condition which was not yet triggered) */
385                         GC_ASSERT(0);
386                         return false;
387
388                 }
389
390         }
391
392         /* this point should never be reached */
393         GC_ASSERT(0);
394
395 }
396 #endif
397
398
399 /* gc_call *********************************************************************
400
401    Forces a full collection of the whole Java Heap.
402    This is the function which is called by java.lang.Runtime.gc()
403
404 *******************************************************************************/
405
406 void gc_call(void)
407 {
408         if (opt_verbosegc)
409                 dolog("GC: Forced Collection ...");
410
411         GCSTAT_COUNT(gcstat_collections_forced);
412
413         gc_collect(0);
414
415         if (opt_verbosegc)
416                 dolog("GC: Forced Collection finished.");
417 }
418
419
420 /* gc_invoke_finalizers ********************************************************
421
422    Forces invocation of all the finalizers for objects which are reclaimable.
423    This is the function which is called by the finalizer thread.
424
425 *******************************************************************************/
426
427 void gc_invoke_finalizers(void)
428 {
429         if (opt_verbosegc)
430                 dolog("GC: Invoking finalizers ...");
431
432         final_invoke();
433
434         if (opt_verbosegc)
435                 dolog("GC: Invoking finalizers finished.");
436 }
437
438
439 /* gc_finalize_all *************************************************************
440
441    Forces the finalization of all objects on the Java Heap.
442    This is the function which is called by java.lang.Runtime.exit()
443
444    We do this by setting all objects with finalizers to reclaimable,
445    which is inherently dangerouse because objects may still be alive.
446
447 *******************************************************************************/
448
449 void gc_finalize_all(void)
450 {
451 #if !defined(NDEBUG)
452         /* doing this is deprecated, inform the user */
453         dolog("gc_finalize_all: Deprecated!");
454 #endif
455
456         /* set all objects with finalizers to reclaimable */
457         final_set_all_reclaimable();
458
459         /* notify the finalizer thread */
460         finalizer_notify();
461 }
462
463
464 /* Informational getter functions *********************************************/
465
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; }
470
471
472 /* Statistics *****************************************************************/
473
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;
480
481 void gcstat_println()
482 {
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);
486
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);
490
491         printf("\nGCSTAT - Compaction Statistics:\n");
492
493         printf("\n");
494 }
495 #endif /* defined(ENABLE_STATISTICS) */
496
497
498 /*
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  * ---------------------------------------------------------------------
503  * Local variables:
504  * mode: c
505  * indent-tabs-mode: t
506  * c-basic-offset: 4
507  * tab-width: 4
508  * End:
509  * vim:noexpandtab:sw=4:ts=4:
510  */