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