* src/vmcore/linker.c (build_display): Removed superfluous recursion; return
[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 zur Foerderung der freien virtuellen Maschine 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/thread.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(list); re != NULL; re = list_next(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(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(list); re != NULL; re = list_next(list, re)) {
191                 if (re->ref == ref) {
192                         /* remove the entry from the given list */
193                         list_remove(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         stacktrace_t *st;
238 #endif
239 #if defined(ENABLE_RT_TIMING)
240         struct timespec time_start, time_suspend, time_rootset, time_mark, time_compact, time_end;
241 #endif
242
243         /* enter the global gc lock */
244         GC_MUTEX_LOCK;
245
246         /* remember start of dump memory area */
247         DMARKER;
248
249         GCSTAT_COUNT(gcstat_collections);
250
251         RT_TIMING_GET_TIME(time_start);
252
253         /* let everyone know we want to do a collection */
254         GC_ASSERT(!gc_pending);
255         gc_pending = true;
256
257         /* finalizer is not notified, unless marking tells us to do so */
258         gc_notify_finalizer = false;
259
260 #if defined(ENABLE_THREADS)
261         /* stop the world here */
262         GC_LOG( dolog("GC: Suspending threads ..."); );
263         GC_LOG( threads_dump(); );
264         threads_stopworld();
265         /*GC_LOG( threads_dump(); );*/
266         GC_LOG( dolog("GC: Suspension finished."); );
267 #endif
268
269 #if !defined(NDEBUG)
270         /* get the stacktrace of the current thread and make sure it is non-empty */
271         GC_LOG( printf("Stacktrace of current thread:\n"); );
272         st = stacktrace_get_current();
273         if (st == NULL)
274                 vm_abort("gc_collect: no stacktrace available for current thread!");
275         GC_LOG( stacktrace_print(st); );
276 #endif
277
278         /* sourcestate of the current thread, assuming we are in the native world */
279         GC_LOG( dolog("GC: Stackwalking current thread ..."); );
280 #if defined(ENABLE_THREADS)
281         GC_ASSERT(THREADOBJECT->flags & THREAD_FLAG_IN_NATIVE);
282 #endif
283         replace_gc_from_native(THREADOBJECT, NULL, NULL);
284
285         /* everyone is halted now, we consider ourselves running */
286         GC_ASSERT(!gc_running);
287         gc_pending = false;
288         gc_running = true;
289
290         RT_TIMING_GET_TIME(time_suspend);
291
292         GC_LOG( heap_println_usage(); );
293         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
294
295         /* find the global and local rootsets */
296         rs = rootset_readout();
297
298 #if !defined(NDEBUG)
299         /* print the rootsets if debugging is enabled */
300         if (opt_GCDebugRootSet)
301                 rootset_print(rs);
302 #endif
303
304         RT_TIMING_GET_TIME(time_rootset);
305
306 #if 1
307
308         /* mark the objects considering the given rootset */
309         mark_me(rs);
310         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
311
312         RT_TIMING_GET_TIME(time_mark);
313
314         /* compact the heap */
315         compact_me(rs, heap_region_main);
316         /*GC_LOG( heap_dump_region(heap_region_main, false); );*/
317
318 #if defined(ENABLE_MEMCHECK)
319         /* invalidate the rest of the main region */
320         region_invalidate(heap_region_main);
321 #endif
322
323         RT_TIMING_GET_TIME(time_compact);
324
325         /* check if we should increase the heap size */
326         if (gc_get_free_bytes() < gc_get_heap_size() / 3) /* TODO: improve this heuristic */
327                 heap_increase_size(rs);
328
329 #else
330
331         /* copy the heap to new region */
332         {
333                 regioninfo_t *src, *dst;
334
335                 src = heap_region_main;
336                 dst = NEW(regioninfo_t);
337                 region_create(dst, heap_current_size);
338                 copy_me(heap_region_main, dst, rs);
339                 heap_region_main = dst;
340
341                 /* invalidate old heap */
342                 memset(src->base, 0x66, src->size);
343         }
344 #endif
345
346         /* TODO: check my return value! */
347         /*heap_increase_size();*/
348
349         /* write back the rootset to update root references */
350         GC_LOG( rootset_print(rs); );
351         rootset_writeback(rs);
352
353 #if defined(ENABLE_STATISTICS)
354         if (opt_verbosegc)
355                 gcstat_println();
356 #endif
357
358         /* we are no longer running */
359         gc_running = false;
360
361 #if defined(ENABLE_THREADS)
362         /* start the world again */
363         GC_LOG( dolog("GC: Reanimating world ..."); );
364         threads_startworld();
365         /*GC_LOG( threads_dump(); );*/
366 #endif
367
368 #if defined(GCCONF_FINALIZER)
369         /* does the finalizer need to be notified */
370         if (gc_notify_finalizer)
371                 finalizer_notify();
372 #endif
373
374         RT_TIMING_GET_TIME(time_end);
375
376         RT_TIMING_TIME_DIFF(time_start  , time_suspend, RT_TIMING_GC_SUSPEND);
377         RT_TIMING_TIME_DIFF(time_suspend, time_rootset, RT_TIMING_GC_ROOTSET1)
378         RT_TIMING_TIME_DIFF(time_rootset, time_mark   , RT_TIMING_GC_MARK);
379         RT_TIMING_TIME_DIFF(time_mark   , time_compact, RT_TIMING_GC_COMPACT);
380         RT_TIMING_TIME_DIFF(time_compact, time_end    , RT_TIMING_GC_ROOTSET2);
381         RT_TIMING_TIME_DIFF(time_start  , time_end    , RT_TIMING_GC_TOTAL);
382
383     /* free dump memory area */
384     DRELEASE;
385
386         /* leave the global gc lock */
387         GC_MUTEX_UNLOCK;
388
389         /* XXX move this to an appropriate place */
390         lock_hashtable_cleanup();
391 }
392
393
394 #if defined(ENABLE_THREADS)
395 bool gc_suspend(threadobject *thread, u1 *pc, u1 *sp)
396 {
397         codeinfo         *code;
398
399         /* check if the thread suspended itself */
400         if (pc == NULL) {
401                 GC_LOG( dolog("GC: Suspended myself!"); );
402                 return true;
403         }
404
405         /* thread was forcefully suspended */
406         GC_LOG( dolog("GC: Suspending thread (tid=%p)", thread->tid); );
407
408         /* check where this thread came to a halt */
409         if (thread->flags & THREAD_FLAG_IN_NATIVE) {
410
411                 if (thread->gc_critical) {
412                         GC_LOG( dolog("\tNATIVE &  CRITICAL -> retry"); );
413
414                         GC_ASSERT(0);
415
416                         /* wait till this thread suspends itself */
417                         return false;
418
419                 } else {
420                         GC_LOG( dolog("\tNATIVE & SAFE -> suspend"); );
421
422                         /* we assume we are in a native! */
423                         replace_gc_from_native(thread, pc, sp);
424
425                         /* suspend me now */
426                         return true;
427
428                 }
429
430         } else {
431                 code = code_find_codeinfo_for_pc_nocheck(pc);
432
433                 if (code != NULL) {
434                         GC_LOG( dolog("\tJIT (pc=%p) & KNOWN(codeinfo=%p) -> replacement",
435                                         pc, code); );
436
437                         /* arm the replacement points of the code this thread is in */
438                         replace_activate_replacement_points(code, false);
439
440                         /* wait till this thread suspends itself */
441                         return false;
442
443                 } else {
444                         GC_LOG( dolog("\tJIT (pc=%p) & UN-KNOWN -> retry", pc); );
445
446                         /* re-suspend me later */
447                         /* TODO: implement me! */
448                         /* TODO: (this is a rare race condition which was not yet triggered) */
449                         GC_ASSERT(0);
450                         return false;
451
452                 }
453
454         }
455
456         /* this point should never be reached */
457         GC_ASSERT(0);
458
459 }
460 #endif
461
462
463 /* gc_call *********************************************************************
464
465    Forces a full collection of the whole Java Heap.
466    This is the function which is called by java.lang.Runtime.gc()
467
468 *******************************************************************************/
469
470 void gc_call(void)
471 {
472         if (opt_verbosegc)
473                 dolog("GC: Forced Collection ...");
474
475         GCSTAT_COUNT(gcstat_collections_forced);
476
477         gc_collect(0);
478
479         if (opt_verbosegc)
480                 dolog("GC: Forced Collection finished.");
481 }
482
483
484 /* gc_invoke_finalizers ********************************************************
485
486    Forces invocation of all the finalizers for objects which are reclaimable.
487    This is the function which is called by the finalizer thread.
488
489 *******************************************************************************/
490
491 void gc_invoke_finalizers(void)
492 {
493         if (opt_verbosegc)
494                 dolog("GC: Invoking finalizers ...");
495
496         final_invoke();
497
498         if (opt_verbosegc)
499                 dolog("GC: Invoking finalizers finished.");
500 }
501
502
503 /* gc_finalize_all *************************************************************
504
505    Forces the finalization of all objects on the Java Heap.
506    This is the function which is called by java.lang.Runtime.exit()
507
508    We do this by setting all objects with finalizers to reclaimable,
509    which is inherently dangerouse because objects may still be alive.
510
511 *******************************************************************************/
512
513 void gc_finalize_all(void)
514 {
515 #if !defined(NDEBUG)
516         /* doing this is deprecated, inform the user */
517         dolog("gc_finalize_all: Deprecated!");
518 #endif
519
520         /* set all objects with finalizers to reclaimable */
521         final_set_all_reclaimable();
522
523         /* notify the finalizer thread */
524         finalizer_notify();
525 }
526
527
528 /* Informational getter functions *********************************************/
529
530 s8 gc_get_heap_size(void)     { return heap_current_size; }
531 s8 gc_get_free_bytes(void)    { return heap_region_main->free; }
532 s8 gc_get_total_bytes(void)   { return heap_region_main->size - heap_region_main->free; }
533 s8 gc_get_max_heap_size(void) { return heap_maximal_size; }
534
535
536 /* Statistics *****************************************************************/
537
538 #if defined(ENABLE_STATISTICS)
539 int gcstat_collections;
540 int gcstat_collections_forced;
541 int gcstat_mark_depth;
542 int gcstat_mark_depth_max;
543 int gcstat_mark_count;
544
545 void gcstat_println()
546 {
547         printf("\nGCSTAT - General Statistics:\n");
548         printf("\t# of collections: %d\n", gcstat_collections);
549         printf("\t# of forced collections: %d\n", gcstat_collections_forced);
550
551     printf("\nGCSTAT - Marking Statistics:\n");
552     printf("\t# of objects marked: %d\n", gcstat_mark_count);
553     printf("\tMaximal marking depth: %d\n", gcstat_mark_depth_max);
554
555         printf("\nGCSTAT - Compaction Statistics:\n");
556
557         printf("\n");
558 }
559 #endif /* defined(ENABLE_STATISTICS) */
560
561
562 /*
563  * These are local overrides for various environment variables in Emacs.
564  * Please do not remove this and leave it at the end of the file, where
565  * Emacs will automagically detect them.
566  * ---------------------------------------------------------------------
567  * Local variables:
568  * mode: c
569  * indent-tabs-mode: t
570  * c-basic-offset: 4
571  * tab-width: 4
572  * End:
573  * vim:noexpandtab:sw=4:ts=4:
574  */