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