CACAO
rootset.c
Go to the documentation of this file.
1 /* mm/cacao-gc/rootset.c - GC module for root set management
2 
3  Copyright (C) 2006, 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 "gc.h"
29 #include "final.h"
30 #include "heap.h"
31 #include "mark.h"
32 
33 #include "mm/memory.hpp"
34 
35 #include "threads/threadlist.h"
36 #include "threads/thread.hpp"
37 
38 #include "toolbox/logging.hpp"
39 
40 #include "vm/global.hpp"
41 #include "vm/jit/replace.hpp"
42 #include "vm/jit/stacktrace.hpp"
43 
44 
46 {
47  rootset_t *rs;
48 
49  /* allocate memory for rootset */
50  rs = DNEW(rootset_t);
51 
52  rs->next = NULL;
54  rs->refcount = 0;
55 
56  return rs;
57 }
58 
59 
61 {
62  s4 size_old;
63  s4 size_new;
64 
65  /* double the capacity of this rootset */
66  size_old = sizeof(rootset_t) + (rs->capacity - ROOTSET_INITIAL_CAPACITY) * sizeof(rootset_entry_t);
67  rs->capacity *= 2;
68  size_new = sizeof(rootset_t) + (rs->capacity - ROOTSET_INITIAL_CAPACITY) * sizeof(rootset_entry_t);
69 
70  GC_LOG2( printf("Resizing rootset to capacity %d (%d -> %d)\n", rs->capacity, size_old, size_new); );
71 
72  /* reallocate memory for rootset */
73  /* XXX DMREALLOC(ptr,type,num1,num2) */
74  rs = DMREALLOC(rs, u1, size_old, size_new);
75 
76  return rs;
77 }
78 
79 
80 /* rootset_from_globals ********************************************************
81 
82  Searches global variables to compile the global root set out of references
83  contained in them.
84 
85  REMEMBER: All threads are stopped, so we don't have to lock the
86  lists in this function.
87 
88  SEARCHES IN:
89  - thread objects (threads.c)
90  - classloader objects (loader.c)
91  - global reference table (jni.c)
92  - finalizer entries (final.c)
93 
94 *******************************************************************************/
95 
96 #define ROOTSET_ADD(adr,mrk,tp) \
97  if (refcount >= rs->capacity) \
98  rs = rootset_resize(rs); \
99  rs->refs[refcount].ref = (adr); \
100  rs->refs[refcount].marks = (mrk); \
101  rs->refs[refcount].reftype = (tp); \
102  refcount++;
103 
105 {
106  list_final_entry_t *fe;
107  list_gcref_entry_t *re;
108  int refcount;
109 
110  GC_LOG( dolog("GC: Acquiring Root-Set from globals ..."); );
111 
112  /* initialize the rootset struct */
113  GC_ASSERT(rs);
114  GC_ASSERT(rs->refcount == 0);
116 
117  refcount = rs->refcount;
118 
119  /* walk through all registered strong references */
120  for (re = list_first(gc_reflist_strong); re != NULL; re = list_next(gc_reflist_strong, re)) {
121  GC_LOG2( printf("Found Registered Reference: %p at %p of type %d\n", *(re->ref), re->ref, ref->reftype); );
122 
123  /* add this registered reference to the root set */
124  ROOTSET_ADD(re->ref, true, re->reftype)
125  }
126 
127  /* walk through all registered weak references */
128  for (re = list_first(gc_reflist_weak); re != NULL; re = list_next(gc_reflist_weak, re)) {
129  GC_LOG2( printf("Found Registered Weak Reference: %p at %p of type %d\n", *(re->ref), re->ref, ref->reftype); );
130 
131  /* add this registered reference to the root set */
132  ROOTSET_ADD(re->ref, false, re->reftype)
133  }
134 
135  /* walk through all finalizer entries */
136  for (fe = list_first(final_list); fe != NULL; fe = list_next(final_list, fe)) {
137  GC_LOG2( printf("Found Finalizer Entry: %p\n", (void *) fe->o); );
138 
139  /* add this object with finalizer to the root set */
140  ROOTSET_ADD(&( fe->o ), false, GC_REFTYPE_FINALIZER)
141  }
142 
143  /* remeber how many references there are inside this root set */
144  rs->refcount = refcount;
145 
146  return rs;
147 }
148 
149 
151 {
152  classinfo *c;
153  fieldinfo *f;
154  void *sys_start, *sys_end;
155  int refcount;
156  int i;
157 
158  GC_LOG( dolog("GC: Acquiring Root-Set from classes ..."); );
159 
160  /* TODO: cleanup!!! */
161  sys_start = heap_region_sys->base;
162  sys_end = heap_region_sys->ptr;
163 
164  refcount = rs->refcount;
165 
166  /* walk through all classinfo blocks */
167  c = sys_start;
168  while (c < (classinfo *) sys_end) {
169 
170  GC_LOG2( printf("Searching in class "); class_print(c); printf("\n"); );
171 
172  /* walk through all fields */
173  f = c->fields;
174  for (i = 0; i < c->fieldscount; i++, f++) {
175 
176  /* check if this is a static reference */
177  if (!IS_ADR_TYPE(f->type) || !(f->flags & ACC_STATIC))
178  continue;
179 
180  /* check for outside or null pointers */
181  if (f->value->a == NULL)
182  continue;
183 
184  GC_LOG2( printf("Found Static Field Reference: %p\n", (void *) f->value->a);
185  printf("\tfrom field: "); field_print(f); printf("\n");
186  printf("\tto object : "); heap_print_object(f->value->a); printf("\n"); );
187 
188  /* add this static field reference to the root set */
189  ROOTSET_ADD(f->value, true, GC_REFTYPE_CLASSREF);
190 
191  }
192 
193  /* skip to next classinfo block */
194  c++;
195  c = (classinfo *) (GC_ALIGN((ptrint) c, GC_ALIGN_SIZE));
196 
197  }
198 
199  /* remeber how many references there are inside this root set */
200  rs->refcount = refcount;
201 
202  return rs;
203 }
204 
205 
206 /* rootset_from_thread *********************************************************
207 
208  Searches the stack of the passed thread for references and compiles a
209  root set out of them.
210 
211  NOTE: uses dump memory!
212 
213  IN:
214  thread...TODO
215  rs.......TODO
216 
217  OUT:
218  TODO!!!
219 
220 *******************************************************************************/
221 
223 {
224  executionstate_t *es;
225  sourcestate_t *ss;
226  sourceframe_t *sf;
227  localref_table *lrt;
228  int refcount;
229  int i;
230 
231 #if defined(ENABLE_THREADS)
232  GC_ASSERT(thread != NULL);
233  GC_LOG( dolog("GC: Acquiring Root-Set from thread (tid=%p) ...", (void *) thread->impl.tid); );
234 #else
235  GC_ASSERT(thread == NULL);
236  GC_LOG( dolog("GC: Acquiring Root-Set from single-thread ..."); );
237 #endif
238 
239  GC_LOG2( printf("Stacktrace of thread:\n");
240  threads_thread_print_stacktrace(thread); );
241 
242  /* get the sourcestate of the threads */
243  es = GC_EXECUTIONSTATE;
244  ss = GC_SOURCESTATE;
245 
246  GC_ASSERT(es);
247  GC_ASSERT(ss);
248 
249  /* print our full source state */
251 
252  /* initialize the rootset struct */
253  GC_ASSERT(rs);
254  GC_ASSERT(rs->refcount == 0);
255  rs->thread = thread;
256 
257  refcount = rs->refcount;
258 
259  /* now inspect the source state to compile the root set */
260  for (sf = ss->frames; sf != NULL; sf = sf->down) {
261 
262  GC_LOG( printf("Source Frame: localcount=%d, stackdepth=%d, syncslots=%d\n", sf->javalocalcount, sf->javastackdepth, sf->syncslotcount); );
263 
264  for (i = 0; i < sf->javalocalcount; i++) {
265 
266  /* we only need to consider references */
267  if (sf->javalocaltype[i] != TYPE_ADR)
268  continue;
269 
270  GC_LOG2( printf("Found Reference (Java Local): %p\n", (void *) sf->javalocals[i].a); );
271 
272  /* add this reference to the root set */
273  ROOTSET_ADD((java_object_t **) &( sf->javalocals[i] ), true, GC_REFTYPE_STACK);
274 
275  }
276 
277  for (i = 0; i < sf->javastackdepth; i++) {
278 
279  /* we only need to consider references */
280  if (sf->javastacktype[i] != TYPE_ADR)
281  continue;
282 
283  GC_LOG2( printf("Found Reference (Java Stack): %p\n", (void *) sf->javastack[i].a); );
284 
285  /* add this reference to the root set */
286  ROOTSET_ADD((java_object_t **) &( sf->javastack[i] ), true, GC_REFTYPE_STACK);
287 
288  }
289 
290  for (i = 0; i < sf->syncslotcount; i++) {
291 
292  GC_LOG( printf("Found Reference (Sync Slot): %p\n", (void *) sf->syncslots[i].a); );
293 
294  /* add this reference to the root set */
295  ROOTSET_ADD((java_object_t **) &( sf->syncslots[i] ), true, GC_REFTYPE_STACK);
296 
297  }
298  }
299 
300  /* now walk through all local references of this thread */
301 #if defined(ENABLE_THREADS)
302  lrt = thread->_localref_table;
303 #else
304  lrt = LOCALREFTABLE;
305 #endif
306  while (lrt) {
307 
308  for (i = 0; i < lrt->used; i++) {
309 
310  /* there should be no null pointers in here */
311  GC_ASSERT(lrt->refs[i] != NULL);
312 
313  GC_LOG2( printf("Found LocalRef: %p\n", (void *) lrt->refs[i]); );
314 
315  /* add this reference to the root set */
316  ROOTSET_ADD(&( lrt->refs[i] ), true, GC_REFTYPE_LOCALREF);
317 
318  }
319 
320  lrt = lrt->prev;
321  }
322 
323  /* remeber how many references there are inside this root set */
324  rs->refcount = refcount;
325 
326  return rs;
327 }
328 
329 
331 {
332  rootset_t *rs_top;
333  rootset_t *rs;
334  threadobject *t;
335 
336  /* find the global rootset ... */
337  rs_top = rootset_create();
338  rs_top = rootset_from_globals(rs_top);
339  rs_top = rootset_from_classes(rs_top);
340 
341  /* ... and the rootsets for the threads */
342  rs = rs_top;
343 #if defined(ENABLE_THREADS)
344  for (t = threadlist_first(); t != NULL; t = threadlist_next(t)) {
345 
346  /* ignore threads which are in state NEW */
347  if (t->state == THREAD_STATE_NEW)
348  continue;
349 
350  rs->next = rootset_create();
351  rs->next = rootset_from_thread(t, rs->next);
352 
353  rs = rs->next;
354  }
355 #else
356  t = THREADOBJECT;
357 
358  rs->next = rootset_create();
359  rs->next = rootset_from_thread(t, rs->next);
360 #endif
361 
362  return rs_top;
363 }
364 
365 
367 {
369 
370  /* walk through all rootsets */
371  while (rs) {
372  thread = rs->thread;
373 
374  /* does this rootset belong to a thread? */
375  if (thread != ROOTSET_DUMMY_THREAD) {
376 #if defined(ENABLE_THREADS)
377  GC_ASSERT(thread != NULL);
378  GC_LOG( dolog("GC: Writing back Root-Set to thread (tid=%p) ...", (void *) thread->impl.tid); );
379 #else
380  GC_ASSERT(thread == NULL);
381  GC_LOG( dolog("GC: Writing back Root-Set to single-thread ..."); );
382 #endif
383 
384  /* now rebuild the stack of the thread */
385  replace_gc_into_native(thread);
386  }
387 
388  rs = rs->next;
389  }
390 
391 }
392 
393 
394 /* Debugging ******************************************************************/
395 
396 #if !defined(NDEBUG)
397 static const char* reftype_names[] = {
398  "THREADOBJECT", "CLASSLOADER ", "GLOBAL-REF ",
399  "FINALIZER ", "LOCAL-REF ", "ON-STACK-ADR",
400  "STATIC FIELD", "LOCKRECORD "
401 };
402 
404 {
405  java_object_t *o;
406  int i;
407 
408  /* walk through all rootsets in the chain */
409  printf("Root Set Chain:\n");
410  while (rs) {
411 
412  /* print the thread this rootset belongs to */
413  if (rs->thread == ROOTSET_DUMMY_THREAD) {
414  printf("\tGlobal Root Set:\n");
415  } else {
416 #if defined(ENABLE_THREADS)
417  printf("\tLocal Root Set with Thread-Id %p:\n", (void *) rs->thread->impl.tid);
418 #else
419  printf("\tLocal Root Set:\n");
420 #endif
421  }
422 
423  /* print the references in this rootset */
424  printf("\tReferences (%d / %d):\n", rs->refcount, rs->capacity);
425  for (i = 0; i < rs->refcount; i++) {
426 
427  o = *( rs->refs[i].ref );
428 
429  /*printf("\t\tReference at %p points to ...\n", (void *) rs->refs[i]);*/
430  printf("\t\t");
431  printf("%s ", reftype_names[rs->refs[i].reftype]);
432  if (rs->refs[i].marks)
433  printf("STRONG");
434  else
435  printf(" WEAK");
436  printf(" ");
438  printf("\n");
439 
440  }
441 
442  rs = rs->next;
443 
444  }
445 
446 }
447 #endif
448 
449 
450 /*
451  * These are local overrides for various environment variables in Emacs.
452  * Please do not remove this and leave it at the end of the file, where
453  * Emacs will automagically detect them.
454  * ---------------------------------------------------------------------
455  * Local variables:
456  * mode: c
457  * indent-tabs-mode: t
458  * c-basic-offset: 4
459  * tab-width: 4
460  * End:
461  * vim:noexpandtab:sw=4:ts=4:
462  */
#define dolog
Definition: logging.hpp:171
static rootset_t * rootset_from_globals(rootset_t *rs)
Definition: rootset.c:104
#define ROOTSET_INITIAL_CAPACITY
Definition: rootset.h:45
rootset_t * next
Definition: rootset.h:60
rootset_entry_t refs[ROOTSET_INITIAL_CAPACITY]
Definition: rootset.h:64
static rootset_t * rootset_from_thread(threadobject *thread, rootset_t *rs)
Definition: rootset.c:222
java_object_t * o
Definition: final.h:53
struct rootset_entry_t rootset_entry_t
#define DMREALLOC(ptr, type, num1, num2)
Definition: dumpmemory.hpp:372
#define GC_SOURCESTATE
Definition: gc.h:149
void class_print(classinfo *c)
Definition: class.cpp:2231
struct rootset_t rootset_t
Definition: rootset.h:29
#define GC_ALIGN_SIZE
Definition: gc.h:108
#define GC_LOG(code)
Definition: gc.h:58
uint8_t u1
Definition: types.hpp:40
list_t * gc_reflist_weak
Definition: gc.c:59
Definition: final.h:50
void replace_sourcestate_println(sourcestate_t *ss)
Definition: replace.cpp:3237
#define DNEW(type)
Definition: dumpmemory.hpp:370
int32_t fieldscount
Definition: class.hpp:109
cacao::detail::threadobject impl
Definition: thread.hpp:91
s4 reftype
Definition: gc.h:129
fieldinfo * fields
Definition: class.hpp:110
u1 * base
Definition: region.h:48
#define GC_ASSERT(assertion)
Definition: gc.h:59
java_object_t ** ref
Definition: rootset.h:51
#define GC_LOG2(code)
Definition: gc.h:68
threadobject * thread
Definition: rootset.h:61
#define ROOTSET_ADD(adr, mrk, tp)
Definition: rootset.c:96
void field_print(fieldinfo *f)
Definition: field.cpp:479
u1 * ptr
Definition: region.h:50
localref_table * _localref_table
Definition: thread.hpp:130
JNIEnv jthread thread
Definition: jvmti.h:207
#define GC_ALIGN(val, size)
Definition: gc.h:109
MIIterator i
regioninfo_t * heap_region_sys
Definition: heap.c:52
int32_t s4
Definition: types.hpp:45
ThreadState state
Definition: thread.hpp:97
void rootset_print(rootset_t *rs)
Definition: rootset.c:403
void heap_print_object(java_object_t *o)
Definition: heap.c:400
rootset_t * rootset_resize(rootset_t *rs)
Definition: rootset.c:60
#define IS_ADR_TYPE(a)
Definition: global.hpp:138
list_t * gc_reflist_strong
Definition: gc.c:58
#define LOCALREFTABLE
Definition: localref.cpp:47
static rootset_t * rootset_from_classes(rootset_t *rs)
Definition: rootset.c:150
list_t * final_list
Definition: final.c:38
void rootset_writeback(rootset_t *rs)
Definition: rootset.c:366
rootset_t * rootset_create(void)
Definition: rootset.c:45
static const char * reftype_names[]
Definition: rootset.c:397
#define GC_EXECUTIONSTATE
Definition: gc.h:148
Definition: gc.h:125
s4 refcount
Definition: rootset.h:63
uintptr_t ptrint
Definition: types.hpp:54
s4 reftype
Definition: rootset.h:54
s4 capacity
Definition: rootset.h:62
union localref_table::@1 refs[LOCALREFTABLE_CAPACITY]
#define printf(...)
Definition: ssa2.cpp:40
#define THREADOBJECT
Definition: thread-none.hpp:47
java_object_t ** ref
Definition: gc.h:127
#define ROOTSET_DUMMY_THREAD
Definition: rootset.h:43
rootset_t * rootset_readout()
Definition: rootset.c:330
localref_table * prev
Definition: localref.hpp:57
bool marks
Definition: rootset.h:52