1 /* mm/cacao-gc/compact.c - GC module for compacting heap regions
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
8 This file is part of CACAO.
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.
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.
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
25 Contact: cacao@cacaojvm.org
27 Authors: Michael Starzinger
40 #include "mm/memory.h"
41 #include "toolbox/logging.h"
44 /* Threading macros ***********************************************************/
46 #define GC_THREAD_BIT 0x01
48 #define GC_IS_THREADED(ptr) (((ptrint) ptr) & GC_THREAD_BIT)
49 #define GC_REMOVE_THREAD_BIT(ptr) (((ptrint) ptr) & ~GC_THREAD_BIT)
50 #define GC_SET_THREAD_BIT(ptr) (((ptrint) ptr) | GC_THREAD_BIT)
52 #define GC_THREAD(ref, refptr, start, end) \
53 if (POINTS_INTO(ref, start, end)) { \
54 GC_ASSERT(GC_IS_MARKED(ref)); \
55 *refptr = (java_objectheader *) ref->vftbl; \
56 ref->vftbl = (struct _vftbl *) GC_SET_THREAD_BIT(refptr); \
60 /* compact_thread_rootset ******************************************************
62 Threads all the references in the rootset
65 rs........Rootset containing the references to be threaded.
66 start.....Region to be compacted start here
67 end.......Region to be compacted ends here
69 *******************************************************************************/
71 void compact_thread_rootset(rootset_t *rs, void *start, void *end)
73 java_objectheader *ref;
74 java_objectheader **refptr;
77 GC_LOG2( printf("threading in rootsets\n"); );
79 /* walk through all rootsets */
82 /* walk through the references of this rootset */
83 for (i = 0; i < rs->refcount; i++) {
85 /* load the reference */
89 GC_LOG2( printf("\troot pointer to %p\n", (void *) ref); );
91 /* thread the references */
92 GC_THREAD(ref, refptr, start, end);
96 /* skip to next rootset in chain */
103 /* compact_thread_classes ******************************************************
105 Threads all the references from classinfo structures (static fields)
108 start.....Region to be compacted start here
109 end.......Region to be compacted ends here
111 *******************************************************************************/
113 void compact_thread_classes(void *start, void *end)
115 java_objectheader *ref;
116 java_objectheader **refptr;
119 /*hashtable_classloader_entry *cle;*/
120 void *sys_start, *sys_end;
123 GC_LOG2( printf("threading in classes\n"); );
125 /* TODO: cleanup!!! */
126 sys_start = heap_region_sys->base;
127 sys_end = heap_region_sys->ptr;
130 /* walk through all classloaders */
131 for (i = 0; i < hashtable_classloader->size; i++) {
132 cle = hashtable_classloader->ptr[i];
136 /* thread the classloader */
137 refptr = &( cle->object );
139 GC_LOG2( printf("\tclassloader from hashtable at %p\n", (void *) ref); );
140 GC_THREAD(ref, refptr, start, end);
147 /* walk through all classinfo blocks */
148 for (c = sys_start; c < (classinfo *) sys_end; c++) {
150 /* thread the classloader */
151 /*refptr = &( c->classloader );
153 GC_LOG2( printf("\tclassloader from classinfo at %p\n", (void *) ref); );
154 GC_THREAD(ref, refptr, start, end);*/
156 /* walk through all fields */
158 for (i = 0; i < c->fieldscount; i++, f++) {
160 /* check if this is a static reference */
161 if (!IS_ADR_TYPE(f->type) || !(f->flags & ACC_STATIC))
164 /* load the reference */
165 refptr = (java_objectheader **) &(f->value);
168 GC_LOG2( printf("\tclass-field points to %p\n", (void *) ref); );
170 printf("\tfield: "); field_print(f); printf("\n");
171 printf("\tclass-field points to ");
174 } else if (GC_IS_THREADED(ref->vftbl)) {
175 printf("(threaded)\n");
177 heap_print_object(ref); printf("\n");
181 /* thread the reference */
182 GC_THREAD(ref, refptr, start, end);
191 /* compact_thread_references ***************************************************
193 Threads all the references of an object.
196 o.........Object containing the references to be threaded.
197 start.....Region to be compacted start here
198 end.......Region to be compacted ends here
200 *******************************************************************************/
202 void compact_thread_references(java_objectheader *o, void *start, void *end)
204 java_objectheader *ref;
205 java_objectheader **refptr;
207 GC_LOG2( printf("threading in ");
208 heap_print_object(o); printf("\n"); );
212 /* walk through the references of an Array */
213 FOREACH_ARRAY_REF(o,ref,refptr,
215 GC_LOG2( printf("\tarray-entry points to %p\n", (void *) ref); );
217 GC_THREAD(ref, refptr, start, end);
223 /* walk through the references of an Object */
224 FOREACH_OBJECT_REF(o,ref,refptr,
226 GC_LOG2( printf("\tobject-field points to %p\n", (void *) ref); );
228 GC_THREAD(ref, refptr, start, end);
236 /* compact_unthread_references *************************************************
238 Unthreads all the references which previousely pointed to an object. The
239 object itself is the head of the threading chain. All the references in the
240 chain once pointed to the object and will point to it's new location
244 o.......Head of the threading chain
245 new.....New Location of the object after compaction
247 *******************************************************************************/
249 void compact_unthread_references(java_objectheader *o, void *new)
251 java_objectheader **refptr;
254 GC_LOG2( printf("unthreading in ...\n"); );
256 /* some quick sanity checks */
258 GC_ASSERT(GC_IS_THREADED(o->vftbl));
260 /* walk down the threaded chain */
261 refptr = (java_objectheader **) (ptrint) o->vftbl;
262 while (GC_IS_THREADED(refptr)) {
264 /* remove the threading bit */
265 refptr = (java_objectheader **) GC_REMOVE_THREAD_BIT(refptr);
267 GC_LOG2( printf("\treference at %p\n", (void *) refptr); );
269 /* update the reference in the chain */
270 tmp = (ptrint) *refptr;
271 *refptr = (java_objectheader *) (ptrint) new;
273 /* skip to the next chain value */
274 refptr = (java_objectheader **) tmp;
278 /* finally restore the original vftbl pointer */
279 o->vftbl = (struct _vftbl *) refptr;
282 GC_LOG2( printf("\t... pointed to "); heap_print_object(o); printf("\n"); );
283 GC_LOG2( printf("\t... now points to %p\n", (void *) new); );
288 /* compact_move ****************************************************************
290 Moves the content (including header) of an object around in memory
292 NOTE: Memory locations may overlap!
293 NOTE: The size of the object can change by moving it around (hashcode)!
296 old......Old Location of the object before compaction
297 new......New Location of the object after compaction
298 size.....Size of the object in bytes
301 New size of the object after moving it
303 *******************************************************************************/
305 u4 compact_move(u1 *old, u1 *new, u4 size)
310 GC_ASSERT(new <= old);
312 /* check if locations overlap */
313 if (new + size < old) {
314 /* overlapping: NO */
316 /* copy old object content to new location */
317 MCOPY(new, old, u1, size);
320 /* invalidate old object */
321 MSET(old, MEMORY_CLEAR_BYTE, u1, size);
325 /* overlapping: YES */
327 GC_LOG2( printf("\tcompact_move(old=%p, new=%p, size=0x%x) overlapps!", old, new, size) );
329 /* copy old object content to new location */
330 MMOVE(new, old, u1, size);
336 /* check if we need to attach the hashcode to the object */
337 if (GC_TEST_FLAGS((java_objectheader *) new, HDRFLAG_HASH_TAKEN)) {
339 /* TODO: move this whole bunch to heap_attach_hashcode() */
341 /* change the flags accordingly */
342 GC_CLEAR_FLAGS((java_objectheader *) new, HDRFLAG_HASH_TAKEN);
343 GC_SET_FLAGS((java_objectheader *) new, HDRFLAG_HASH_ATTACHED);
345 /* attach the hashcode at the end of the object */
346 new_size += SIZEOF_VOID_P;
347 hashcode = (s4) (ptrint) old;
348 *( (s4 *) (new + new_size - SIZEOF_VOID_P) ) = hashcode; /* TODO: clean this up */
350 GC_ASSERT(new + SIZEOF_VOID_P < old);
351 GC_LOG2( dolog("GC: Hash attached: %d (0x%08x) to new object at %p", hashcode, hashcode, new); );
359 /* compact_me ******************************************************************
361 This function actually does the compaction in two passes. Look at the source
362 for further details about the passes.
365 rs.........Rootset, needed to update the root references
366 region.....Region to be compacted
368 *******************************************************************************/
370 void compact_me(rootset_t *rs, regioninfo_t *region)
374 java_objectheader *o;
379 GC_LOG( dolog("GC: Compaction Phase 0 started ..."); );
382 * - thread all references in classes
383 * - thread all references in the rootset */
384 /*compact_thread_classes(region->base, region->ptr);*/
385 compact_thread_rootset(rs, region->base, region->ptr);
387 GC_LOG( dolog("GC: Compaction Phase 1 started ..."); );
391 * - thread all references
392 * - update forward references */
393 ptr = region->base; ptr_new = region->base;
394 while (ptr < region->ptr) {
395 o = (java_objectheader *) ptr;
397 /* uncollectable items should never be compacted */
398 GC_ASSERT(!GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE));
400 /* if this object is already part of a threaded chain ... */
401 if (GC_IS_THREADED(o->vftbl)) {
403 /* ... unthread the reference chain */
404 compact_unthread_references(o, ptr_new);
408 /* get the object size (objectheader is now unthreaded) */
409 o_size = get_object_size(o);
411 /* only marked objects survive */
412 if (GC_IS_MARKED(o)) {
414 #if defined(GCCONF_HDRFLAG_REFERENCING)
415 /* check if this objects contains references */
416 if (GC_TEST_FLAGS(o, HDRFLAG_REFERENCING))
419 /* thread all the references in this object */
420 compact_thread_references(o, region->base, region->ptr);
422 /* object survives, place next object behind it */
425 /* size might change because of attached hashcode */
426 if (GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN))
427 ptr_new += SIZEOF_VOID_P;
430 /* skip to next object */
434 GC_LOG( dolog("GC: Compaction Phase 2 started ..."); );
437 * - scan the heap again
438 * - update backward references
439 * - move the objects */
441 ptr = region->base; ptr_new = region->base;
442 while (ptr < region->ptr) {
443 o = (java_objectheader *) ptr;
445 /* if this object is still part of a threaded chain ... */
446 if (GC_IS_THREADED(o->vftbl)) {
448 /* ... unthread the reference chain */
449 compact_unthread_references(o, ptr_new);
453 /* get the object size (objectheader is now unthreaded) */
454 o_size = get_object_size(o);
456 /* move the surviving objects */
457 if (GC_IS_MARKED(o)) {
459 GC_LOG2( printf("moving: %08x -> %08x (%d bytes)\n",
460 (ptrint) ptr, (ptrint) ptr_new, o_size); );
462 /* unmark the object */
465 /* move the object (size can change) */
466 o_size_new = compact_move(ptr, ptr_new, o_size);
468 /* object survives, place next object behind it */
469 ptr_new += o_size_new;
473 /* skip to next object */
477 GC_LOG( dolog("GC: Compaction finished."); );
479 GC_LOG( printf("Region-Used: %d -> %d\n", region->size - region->free, used); )
480 GC_LOG( printf("Region-Free: %d -> %d\n", region->free, region->size - used); )
482 /* update the region information */
483 region->ptr = ptr_new;
484 region->free = region->size - used;
490 * These are local overrides for various environment variables in Emacs.
491 * Please do not remove this and leave it at the end of the file, where
492 * Emacs will automagically detect them.
493 * ---------------------------------------------------------------------
496 * indent-tabs-mode: t
500 * vim:noexpandtab:sw=4:ts=4: