* src/mm/cacao-gc/gc.c (gc_reference_unregister): Added.
[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 void gc_reference_unregister(java_objectheader **ref)
147 {
148         vm_abort("gc_reference_unregister: IMPLEMENT ME!");
149 }
150
151
152 /* gc_collect ******************************************************************
153
154    This is the main machinery which manages a collection. It should be run by
155    the thread which triggered the collection.
156
157    IN:
158      XXX
159
160    STEPS OF A COLLECTION:
161      XXX
162
163 *******************************************************************************/
164
165 void gc_collect(s4 level)
166 {
167         rootset_t    *rs;
168         s4            dumpsize;
169 #if !defined(NDEBUG)
170         stackframeinfo   *sfi;
171         stacktracebuffer *stb;
172 #endif
173 #if defined(ENABLE_RT_TIMING)
174         struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
175 #endif
176
177         /* enter the global gc lock */
178         LOCK_MONITOR_ENTER(gc_global_lock);
179
180         /* remember start of dump memory area */
181         dumpsize = dump_size();
182
183         GCSTAT_COUNT(gcstat_collections);
184
185         RT_TIMING_GET_TIME(time_start);
186
187         /* let everyone know we want to do a collection */
188         GC_ASSERT(!gc_pending);
189         gc_pending = true;
190
191         /* finalizer is not notified, unless marking tells us to do so */
192         gc_notify_finalizer = false;
193
194 #if defined(ENABLE_THREADS)
195         /* stop the world here */
196         GC_LOG( dolog("GC: Suspending threads ..."); );
197         GC_LOG( threads_dump(); );
198         threads_stopworld();
199         /*GC_LOG( threads_dump(); );*/
200         GC_LOG( dolog("GC: Suspension finished."); );
201 #endif
202
203 #if !defined(NDEBUG)
204         /* get the stacktrace of the current thread and make sure it is non-empty */
205         GC_LOG( printf("Stacktrace of current thread:\n"); );
206         sfi = STACKFRAMEINFO;
207         stb = stacktrace_create(sfi);
208         if (stb == NULL)
209                 vm_abort("gc_collect: no stacktrace available for current thread!");
210         GC_LOG( stacktrace_print_trace_from_buffer(stb); );
211 #endif
212
213         /* sourcestate of the current thread, assuming we are in the native world */
214         GC_LOG( dolog("GC: Stackwalking current thread ..."); );
215 #if defined(ENABLE_THREADS)
216         GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
217 #endif
218         replace_gc_from_native(THREADOBJECT, NULL, NULL);
219
220         /* everyone is halted now, we consider ourselves running */
221         GC_ASSERT(!gc_running);
222         gc_pending = false;
223         gc_running = true;
224
225         RT_TIMING_GET_TIME(time_suspend);
226
227         GC_LOG( heap_println_usage(); );
228         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
229
230         /* find the global and local rootsets */
231         rs = rootset_readout();
232         GC_LOG( rootset_print(rs); );
233
234         RT_TIMING_GET_TIME(time_rootset);
235
236 #if 1
237
238         /* mark the objects considering the given rootset */
239         mark_me(rs);
240         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
241
242         RT_TIMING_GET_TIME(time_mark);
243
244         /* compact the heap */
245         compact_me(rs, heap_region_main);
246         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
247
248 #if defined(ENABLE_MEMCHECK)
249         /* invalidate the rest of the main region */
250         region_invalidate(heap_region_main);
251 #endif
252
253         RT_TIMING_GET_TIME(time_compact);
254
255         /* check if we should increase the heap size */
256         if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
257                 heap_increase_size(rs);
258
259 #else
260
261         /* copy the heap to new region */
262         {
263                 regioninfo_t *src, *dst;
264
265                 src = heap_region_main;
266                 dst = NEW(regioninfo_t);
267                 region_create(dst, heap_current_size);
268                 copy_me(heap_region_main, dst, rs);
269                 heap_region_main = dst;
270
271                 /* invalidate old heap */
272                 memset(src->base, 0x66, src->size);
273         }
274 #endif
275
276         /* TODO: check my return value! */
277         /*heap_increase_size();*/
278
279         /* write back the rootset to update root references */
280         GC_LOG( rootset_print(rs); );
281         rootset_writeback(rs);
282
283 #if defined(ENABLE_STATISTICS)
284         if (opt_verbosegc)
285                 gcstat_println();
286 #endif
287
288         /* we are no longer running */
289         gc_running = false;
290
291 #if defined(ENABLE_THREADS)
292         /* start the world again */
293         GC_LOG( dolog("GC: Reanimating world ..."); );
294         threads_startworld();
295         /*GC_LOG( threads_dump(); );*/
296 #endif
297
298 #if defined(GCCONF_FINALIZER)
299         /* does the finalizer need to be notified */
300         if (gc_notify_finalizer)
301                 finalizer_notify();
302 #endif
303
304         RT_TIMING_GET_TIME(time_end);
305
306         RT_TIMING_TIME_DIFF(time_start  , time_suspend, RT_TIMING_GC_SUSPEND);
307         RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
308         RT_TIMING_TIME_DIFF(time_rootset, time_mark   , RT_TIMING_GC_MARK);
309         RT_TIMING_TIME_DIFF(time_mark   , time_compact, RT_TIMING_GC_COMPACT);
310         RT_TIMING_TIME_DIFF(time_compact, time_end    , RT_TIMING_GC_ROOTSET2);
311         RT_TIMING_TIME_DIFF(time_start  , time_end    , RT_TIMING_GC_TOTAL);
312
313     /* free dump memory area */
314     dump_release(dumpsize);
315
316         /* leave the global gc lock */
317         LOCK_MONITOR_EXIT(gc_global_lock);
318
319 }
320
321
322 #if defined(ENABLE_THREADS)
323 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
324 {
325         codeinfo         *code;
326
327         /* check if the thread suspended itself */
328         if (pc == NULL) {
329                 GC_LOG( dolog("GC: Suspended myself!"); );
330                 return true;
331         }
332
333         /* thread was forcefully suspended */
334         GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
335
336         /* check where this thread came to a halt */
337         if (thread->flags & THREAD_FLAG_IN_NATIVE) {
338
339                 if (thread->gc_critical) {
340                         GC_LOG( dolog("\tNATIVE &  CRITICAL -> retry"); );
341
342                         GC_ASSERT(0);
343
344                         /* wait till this thread suspends itself */
345                         return false;
346
347                 } else {
348                         GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
349
350                         /* we assume we are in a native! */
351                         replace_gc_from_native(thread, pc, sp);
352
353                         /* suspend me now */
354                         return true;
355
356                 }
357
358         } else {
359                 code = code_find_codeinfo_for_pc_nocheck(pc);
360
361                 if (code != NULL) {
362                         GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
363                                         pc, code); );
364
365                         /* arm the replacement points of the code this thread is in */
366                         replace_activate_replacement_points(code, false);
367
368                         /* wait till this thread suspends itself */
369                         return false;
370
371                 } else {
372                         GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
373
374                         /* re-suspend me later */
375                         /* TODO: implement me! */
376                         /* TODO: (this is a rare race condition which was not yet triggered) */
377                         GC_ASSERT(0);
378                         return false;
379
380                 }
381
382         }
383
384         /* this point should never be reached */
385         GC_ASSERT(0);
386
387 }
388 #endif
389
390
391 /* gc_call *********************************************************************
392
393    Forces a full collection of the whole Java Heap.
394    This is the function which is called by java.lang.Runtime.gc()
395
396 *******************************************************************************/
397
398 void gc_call(void)
399 {
400         if (opt_verbosegc)
401                 dolog("GC: Forced Collection ...");
402
403         GCSTAT_COUNT(gcstat_collections_forced);
404
405         gc_collect(0);
406
407         if (opt_verbosegc)
408                 dolog("GC: Forced Collection finished.");
409 }
410
411
412 /* gc_invoke_finalizers ********************************************************
413
414    Forces invocation of all the finalizers for objects which are reclaimable.
415    This is the function which is called by the finalizer thread.
416
417 *******************************************************************************/
418
419 void gc_invoke_finalizers(void)
420 {
421         if (opt_verbosegc)
422                 dolog("GC: Invoking finalizers ...");
423
424         final_invoke();
425
426         if (opt_verbosegc)
427                 dolog("GC: Invoking finalizers finished.");
428 }
429
430
431 /* gc_finalize_all *************************************************************
432
433    Forces the finalization of all objects on the Java Heap.
434    This is the function which is called by java.lang.Runtime.exit()
435
436    We do this by setting all objects with finalizers to reclaimable,
437    which is inherently dangerouse because objects may still be alive.
438
439 *******************************************************************************/
440
441 void gc_finalize_all(void)
442 {
443 #if !defined(NDEBUG)
444         /* doing this is deprecated, inform the user */
445         dolog("gc_finalize_all: Deprecated!");
446 #endif
447
448         /* set all objects with finalizers to reclaimable */
449         final_set_all_reclaimable();
450
451         /* notify the finalizer thread */
452         finalizer_notify();
453 }
454
455
456 /* Informational getter functions *********************************************/
457
458 s8 gc_get_heap_size(void)     { return heap_current_size; }
459 s8 gc_get_free_bytes(void)    { return heap_region_main->free; }
460 s8 gc_get_total_bytes(void)   { return heap_region_main->size - heap_region_main->free; }
461 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
462
463
464 /* Statistics *****************************************************************/
465
466 #if defined(ENABLE_STATISTICS)
467 int gcstat_collections;
468 int gcstat_collections_forced;
469 int gcstat_mark_depth;
470 int gcstat_mark_depth_max;
471 int gcstat_mark_count;
472
473 void gcstat_println()
474 {
475         printf("\nGCSTAT - General Statistics:\n");
476         printf("\t# of collections: %d\n", gcstat_collections);
477         printf("\t# of forced collections: %d\n", gcstat_collections_forced);
478
479     printf("\nGCSTAT - Marking Statistics:\n");
480     printf("\t# of objects marked: %d\n", gcstat_mark_count);
481     printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
482
483         printf("\nGCSTAT - Compaction Statistics:\n");
484
485         printf("\n");
486 }
487 #endif /* defined(ENABLE_STATISTICS) */
488
489
490 /*
491  * These are local overrides for various environment variables in Emacs.
492  * Please do not remove this and leave it at the end of the file, where
493  * Emacs will automagically detect them.
494  * ---------------------------------------------------------------------
495  * Local variables:
496  * mode: c
497  * indent-tabs-mode: t
498  * c-basic-offset: 4
499  * tab-width: 4
500  * End:
501  * vim:noexpandtab:sw=4:ts=4:
502  */