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