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