f2739cbdbf6307cd498fe5ec8efe334dc81e8c20
[cacao.git] / src / mm / cacao-gc / gc.c
1 /* src/mm/cacao-gc/gc.c - main garbage collector methods
2
3    Copyright (C) 2006, 2007, 2008
4    CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <signal.h>
29 #include <stdint.h>
30
31 #include "vm/types.h"
32
33 #include "threads/lock-common.h"
34 #include "threads/threads-common.h"
35
36 #include "compact.h"
37 #include "copy.h"
38 #include "final.h"
39 #include "gc.h"
40 #include "heap.h"
41 #include "mark.h"
42 #include "region.h"
43 #include "rootset.h"
44 #include "mm/memory.h"
45 #include "toolbox/logging.h"
46 #include "vm/finalizer.h"
47 #include "vm/vm.h"
48 #include "vmcore/rt-timing.h"
49
50
51 /* Global Variables ***********************************************************/
52
53 bool gc_pending;
54 bool gc_running;
55 bool gc_notify_finalizer;
56
57 list_t *gc_reflist_strong;
58 list_t *gc_reflist_weak;
59
60 #if !defined(ENABLE_THREADS)
61 executionstate_t *_no_threads_executionstate;
62 sourcestate_t    *_no_threads_sourcestate;
63 #endif
64
65
66 /* gc_init *********************************************************************
67
68    Initializes the garbage collector.
69
70 *******************************************************************************/
71
72 #define GC_SYS_SIZE (20*1024*1024)
73
74 void gc_init(u4 heapmaxsize, u4 heapstartsize)
75 {
76         if (opt_verbosegc)
77                 dolog("GC: Initialising with heap-size %d (max. %d)",
78                         heapstartsize, heapmaxsize);
79
80 #if defined(ENABLE_HANDLES)
81         /* check our indirection cells */
82         if (OFFSET(java_handle_t, heap_object) != 0)
83                 vm_abort("gc_init: indirection cell offset is displaced: %d", OFFSET(java_handle_t, heap_object));
84         if (OFFSET(hashtable_classloader_entry, object) != 0)
85                 vm_abort("gc_init: classloader entry cannot be used as indirection cell: %d", OFFSET(hashtable_classloader_entry, object));
86         if (OFFSET(hashtable_global_ref_entry, o) != 0)
87                 vm_abort("gc_init: global reference entry cannot be used as indirection cell: %d", OFFSET(hashtable_global_ref_entry, o));
88 #endif
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_strong = list_create(OFFSET(list_gcref_entry_t, linkage));
99         gc_reflist_weak   = list_create(OFFSET(list_gcref_entry_t, linkage));
100
101         /* region for uncollectable objects */
102         heap_region_sys = NEW(regioninfo_t);
103         if (!region_create(heap_region_sys, GC_SYS_SIZE))
104                 vm_abort("gc_init: region_create failed: out of memory");
105
106         /* region for java objects */
107         heap_region_main = NEW(regioninfo_t);
108         if (!region_create(heap_region_main, heapstartsize))
109                 vm_abort("gc_init: region_create failed: out of memory");
110
111         heap_current_size = heapstartsize;
112         heap_maximal_size = heapmaxsize;
113 }
114
115
116 /* gc_reference_register *******************************************************
117
118    Register an external reference which points onto the Heap. The
119    reference needs to be cleared (set to NULL) when registering and
120    has to be set after it has been registered (to avoid a race condition).
121    
122    STRONG REFERENCE: gets updated and keeps objects alive
123    WEAK REFERENCE:   only gets updated (or maybe cleared)
124
125 *******************************************************************************/
126
127 static void gc_reference_register_intern(list_t *list, java_object_t **ref, int32_t reftype)
128 {
129         list_gcref_entry_t *re;
130
131         /* the global GC lock also guards the reference lists */
132         GC_MUTEX_LOCK;
133
134         GC_LOG2( printf("Registering Reference at %p\n", (void *) ref); );
135
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);
139
140 #if !defined(NDEBUG)
141         /* check if this reference is already registered */
142         for (re = list_first_unsynced(list); re != NULL; re = list_next_unsynced(list, re)) {
143                 if (re->ref == ref)
144                         vm_abort("gc_reference_register_intern: reference already registered");
145         }
146 #endif
147
148         /* create a new reference entry */
149         re = NEW(list_gcref_entry_t);
150
151         re->ref     = ref;
152 #if !defined(NDEBUG)
153         re->reftype = reftype;
154 #endif
155
156         /* add the entry to the given list */
157         list_add_last_unsynced(list, re);
158
159         /* the global GC lock also guards the reference lists */
160         GC_MUTEX_UNLOCK;
161 }
162
163 void gc_reference_register(java_object_t **ref, int32_t reftype)
164 {
165         gc_reference_register_intern(gc_reflist_strong, ref, reftype);
166 }
167
168 void gc_weakreference_register(java_object_t **ref, int32_t reftype)
169 {
170         gc_reference_register_intern(gc_reflist_weak, ref, reftype);
171 }
172
173
174 /* gc_reference_unregister *****************************************************
175
176    Unregister a previously registered external reference.
177
178 *******************************************************************************/
179
180 static void gc_reference_unregister_intern(list_t *list, java_object_t **ref)
181 {
182         list_gcref_entry_t *re;
183
184         /* the global GC lock also guards the reference lists */
185         GC_MUTEX_LOCK;
186
187         GC_LOG2( printf("Un-Registering Reference at %p\n", (void *) ref); );
188
189         /* search for the appropriate reference entry */
190         for (re = list_first_unsynced(list); re != NULL; re = list_next_unsynced(list, re)) {
191                 if (re->ref == ref) {
192                         /* remove the entry from the given list */
193                         list_remove_unsynced(list, re);
194
195                         /* free the reference entry */
196                         FREE(re, list_gcref_entry_t);
197
198                         break;
199                 }
200         }
201
202         vm_abort("gc_reference_unregister_intern: reference not found");
203
204         /* the global GC lock also guards the reference lists */
205         GC_MUTEX_UNLOCK;
206 }
207
208 void gc_reference_unregister(java_object_t **ref)
209 {
210         gc_reference_unregister_intern(gc_reflist_strong, ref);
211 }
212
213 void gc_weakreference_unregister(java_object_t **ref)
214 {
215         gc_reference_unregister_intern(gc_reflist_weak, ref);
216 }
217
218
219 /* gc_collect ******************************************************************
220
221    This is the main machinery which manages a collection. It should be run by
222    the thread which triggered the collection.
223
224    IN:
225      XXX
226
227    STEPS OF A COLLECTION:
228      XXX
229
230 *******************************************************************************/
231
232 void gc_collect(s4 level)
233 {
234         rootset_t    *rs;
235         int32_t       dumpmarker;
236 #if !defined(NDEBUG)
237         stackframeinfo_t *sfi;
238         stacktracebuffer *stb;
239 #endif
240 #if defined(ENABLE_RT_TIMING)
241         struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
242 #endif
243
244         /* enter the global gc lock */
245         GC_MUTEX_LOCK;
246
247         /* remember start of dump memory area */
248         DMARKER;
249
250         GCSTAT_COUNT(gcstat_collections);
251
252         RT_TIMING_GET_TIME(time_start);
253
254         /* let everyone know we want to do a collection */
255         GC_ASSERT(!gc_pending);
256         gc_pending = true;
257
258         /* finalizer is not notified, unless marking tells us to do so */
259         gc_notify_finalizer = false;
260
261 #if defined(ENABLE_THREADS)
262         /* stop the world here */
263         GC_LOG( dolog("GC: Suspending threads ..."); );
264         GC_LOG( threads_dump(); );
265         threads_stopworld();
266         /*GC_LOG( threads_dump(); );*/
267         GC_LOG( dolog("GC: Suspension finished."); );
268 #endif
269
270 #if !defined(NDEBUG)
271         /* get the stacktrace of the current thread and make sure it is non-empty */
272         GC_LOG( printf("Stacktrace of current thread:\n"); );
273         sfi = STACKFRAMEINFO;
274         stb = stacktrace_create(sfi);
275         if (stb == NULL)
276                 vm_abort("gc_collect: no stacktrace available for current thread!");
277         GC_LOG( stacktrace_print_trace_from_buffer(stb); );
278 #endif
279
280         /* sourcestate of the current thread, assuming we are in the native world */
281         GC_LOG( dolog("GC: Stackwalking current thread ..."); );
282 #if defined(ENABLE_THREADS)
283         GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
284 #endif
285         replace_gc_from_native(THREADOBJECT, NULL, NULL);
286
287         /* everyone is halted now, we consider ourselves running */
288         GC_ASSERT(!gc_running);
289         gc_pending = false;
290         gc_running = true;
291
292         RT_TIMING_GET_TIME(time_suspend);
293
294         GC_LOG( heap_println_usage(); );
295         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
296
297         /* find the global and local rootsets */
298         rs = rootset_readout();
299
300 #if !defined(NDEBUG)
301         /* print the rootsets if debugging is enabled */
302         if (opt_GCDebugRootSet)
303                 rootset_print(rs);
304 #endif
305
306         RT_TIMING_GET_TIME(time_rootset);
307
308 #if 1
309
310         /* mark the objects considering the given rootset */
311         mark_me(rs);
312         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
313
314         RT_TIMING_GET_TIME(time_mark);
315
316         /* compact the heap */
317         compact_me(rs, heap_region_main);
318         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
319
320 #if defined(ENABLE_MEMCHECK)
321         /* invalidate the rest of the main region */
322         region_invalidate(heap_region_main);
323 #endif
324
325         RT_TIMING_GET_TIME(time_compact);
326
327         /* check if we should increase the heap size */
328         if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
329                 heap_increase_size(rs);
330
331 #else
332
333         /* copy the heap to new region */
334         {
335                 regioninfo_t *src, *dst;
336
337                 src = heap_region_main;
338                 dst = NEW(regioninfo_t);
339                 region_create(dst, heap_current_size);
340                 copy_me(heap_region_main, dst, rs);
341                 heap_region_main = dst;
342
343                 /* invalidate old heap */
344                 memset(src->base, 0x66, src->size);
345         }
346 #endif
347
348         /* TODO: check my return value! */
349         /*heap_increase_size();*/
350
351         /* write back the rootset to update root references */
352         GC_LOG( rootset_print(rs); );
353         rootset_writeback(rs);
354
355 #if defined(ENABLE_STATISTICS)
356         if (opt_verbosegc)
357                 gcstat_println();
358 #endif
359
360         /* we are no longer running */
361         gc_running = false;
362
363 #if defined(ENABLE_THREADS)
364         /* start the world again */
365         GC_LOG( dolog("GC: Reanimating world ..."); );
366         threads_startworld();
367         /*GC_LOG( threads_dump(); );*/
368 #endif
369
370 #if defined(GCCONF_FINALIZER)
371         /* does the finalizer need to be notified */
372         if (gc_notify_finalizer)
373                 finalizer_notify();
374 #endif
375
376         RT_TIMING_GET_TIME(time_end);
377
378         RT_TIMING_TIME_DIFF(time_start  , time_suspend, RT_TIMING_GC_SUSPEND);
379         RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
380         RT_TIMING_TIME_DIFF(time_rootset, time_mark   , RT_TIMING_GC_MARK);
381         RT_TIMING_TIME_DIFF(time_mark   , time_compact, RT_TIMING_GC_COMPACT);
382         RT_TIMING_TIME_DIFF(time_compact, time_end    , RT_TIMING_GC_ROOTSET2);
383         RT_TIMING_TIME_DIFF(time_start  , time_end    , RT_TIMING_GC_TOTAL);
384
385     /* free dump memory area */
386     DRELEASE;
387
388         /* leave the global gc lock */
389         GC_MUTEX_UNLOCK;
390
391         /* XXX move this to an appropriate place */
392         lock_hashtable_cleanup();
393 }
394
395
396 #if defined(ENABLE_THREADS)
397 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
398 {
399         codeinfo         *code;
400
401         /* check if the thread suspended itself */
402         if (pc == NULL) {
403                 GC_LOG( dolog("GC: Suspended myself!"); );
404                 return true;
405         }
406
407         /* thread was forcefully suspended */
408         GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
409
410         /* check where this thread came to a halt */
411         if (thread->flags & THREAD_FLAG_IN_NATIVE) {
412
413                 if (thread->gc_critical) {
414                         GC_LOG( dolog("\tNATIVE &  CRITICAL -> retry"); );
415
416                         GC_ASSERT(0);
417
418                         /* wait till this thread suspends itself */
419                         return false;
420
421                 } else {
422                         GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
423
424                         /* we assume we are in a native! */
425                         replace_gc_from_native(thread, pc, sp);
426
427                         /* suspend me now */
428                         return true;
429
430                 }
431
432         } else {
433                 code = code_find_codeinfo_for_pc_nocheck(pc);
434
435                 if (code != NULL) {
436                         GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
437                                         pc, code); );
438
439                         /* arm the replacement points of the code this thread is in */
440                         replace_activate_replacement_points(code, false);
441
442                         /* wait till this thread suspends itself */
443                         return false;
444
445                 } else {
446                         GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
447
448                         /* re-suspend me later */
449                         /* TODO: implement me! */
450                         /* TODO: (this is a rare race condition which was not yet triggered) */
451                         GC_ASSERT(0);
452                         return false;
453
454                 }
455
456         }
457
458         /* this point should never be reached */
459         GC_ASSERT(0);
460
461 }
462 #endif
463
464
465 /* gc_call *********************************************************************
466
467    Forces a full collection of the whole Java Heap.
468    This is the function which is called by java.lang.Runtime.gc()
469
470 *******************************************************************************/
471
472 void gc_call(void)
473 {
474         if (opt_verbosegc)
475                 dolog("GC: Forced Collection ...");
476
477         GCSTAT_COUNT(gcstat_collections_forced);
478
479         gc_collect(0);
480
481         if (opt_verbosegc)
482                 dolog("GC: Forced Collection finished.");
483 }
484
485
486 /* gc_invoke_finalizers ********************************************************
487
488    Forces invocation of all the finalizers for objects which are reclaimable.
489    This is the function which is called by the finalizer thread.
490
491 *******************************************************************************/
492
493 void gc_invoke_finalizers(void)
494 {
495         if (opt_verbosegc)
496                 dolog("GC: Invoking finalizers ...");
497
498         final_invoke();
499
500         if (opt_verbosegc)
501                 dolog("GC: Invoking finalizers finished.");
502 }
503
504
505 /* gc_finalize_all *************************************************************
506
507    Forces the finalization of all objects on the Java Heap.
508    This is the function which is called by java.lang.Runtime.exit()
509
510    We do this by setting all objects with finalizers to reclaimable,
511    which is inherently dangerouse because objects may still be alive.
512
513 *******************************************************************************/
514
515 void gc_finalize_all(void)
516 {
517 #if !defined(NDEBUG)
518         /* doing this is deprecated, inform the user */
519         dolog("gc_finalize_all: Deprecated!");
520 #endif
521
522         /* set all objects with finalizers to reclaimable */
523         final_set_all_reclaimable();
524
525         /* notify the finalizer thread */
526         finalizer_notify();
527 }
528
529
530 /* Informational getter functions *********************************************/
531
532 s8 gc_get_heap_size(void)     { return heap_current_size; }
533 s8 gc_get_free_bytes(void)    { return heap_region_main->free; }
534 s8 gc_get_total_bytes(void)   { return heap_region_main->size - heap_region_main->free; }
535 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
536
537
538 /* Statistics *****************************************************************/
539
540 #if defined(ENABLE_STATISTICS)
541 int gcstat_collections;
542 int gcstat_collections_forced;
543 int gcstat_mark_depth;
544 int gcstat_mark_depth_max;
545 int gcstat_mark_count;
546
547 void gcstat_println()
548 {
549         printf("\nGCSTAT - General Statistics:\n");
550         printf("\t# of collections: %d\n", gcstat_collections);
551         printf("\t# of forced collections: %d\n", gcstat_collections_forced);
552
553     printf("\nGCSTAT - Marking Statistics:\n");
554     printf("\t# of objects marked: %d\n", gcstat_mark_count);
555     printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
556
557         printf("\nGCSTAT - Compaction Statistics:\n");
558
559         printf("\n");
560 }
561 #endif /* defined(ENABLE_STATISTICS) */
562
563
564 /*
565  * These are local overrides for various environment variables in Emacs.
566  * Please do not remove this and leave it at the end of the file, where
567  * Emacs will automagically detect them.
568  * ---------------------------------------------------------------------
569  * Local variables:
570  * mode: c
571  * indent-tabs-mode: t
572  * c-basic-offset: 4
573  * tab-width: 4
574  * End:
575  * vim:noexpandtab:sw=4:ts=4:
576  */