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
34 #include "mm/memory.hpp"
35 #include "toolbox/logging.hpp"
38 /* Threading macros ***********************************************************/
40 #define GC_THREAD_BIT 0x01
42 #define GC_IS_THREADED(ptr) (((ptrint) ptr) & GC_THREAD_BIT)
43 #define GC_REMOVE_THREAD_BIT(ptr) (((ptrint) ptr) & ~GC_THREAD_BIT)
44 #define GC_SET_THREAD_BIT(ptr) (((ptrint) ptr) | GC_THREAD_BIT)
46 #define GC_THREAD(ref, refptr, start, end) \
47 if (POINTS_INTO(ref, start, end)) { \
48 GC_ASSERT(GC_IS_MARKED(ref)); \
49 *refptr = (java_object_t *) ref->vftbl; \
50 ref->vftbl = (struct _vftbl *) GC_SET_THREAD_BIT(refptr); \
54 /* compact_thread_rootset ******************************************************
56 Threads all the references in the rootset
59 rs........Rootset containing the references to be threaded.
60 start.....Region to be compacted start here
61 end.......Region to be compacted ends here
63 *******************************************************************************/
65 static void compact_thread_rootset(rootset_t *rs, void *start, void *end)
68 java_object_t **refptr;
71 GC_LOG2( printf("threading in rootsets\n"); );
73 /* walk through all rootsets */
76 /* walk through the references of this rootset */
77 for (i = 0; i < rs->refcount; i++) {
79 /* load the reference */
80 refptr = rs->refs[i].ref;
83 GC_LOG2( printf("\troot pointer to %p\n", (void *) ref); );
85 /* thread the references */
86 GC_THREAD(ref, refptr, start, end);
90 /* skip to next rootset in chain */
97 /* compact_thread_references ***************************************************
99 Threads all the references of an object.
102 o.........Object containing the references to be threaded.
103 start.....Region to be compacted start here
104 end.......Region to be compacted ends here
106 *******************************************************************************/
108 static void compact_thread_references(java_object_t *o, void *start, void *end)
111 java_object_t **refptr;
113 GC_LOG2( printf("threading in ");
114 heap_print_object(o); printf("\n"); );
118 /* walk through the references of an Array */
119 FOREACH_ARRAY_REF(o,ref,refptr,
121 GC_LOG2( printf("\tarray-entry points to %p\n", (void *) ref); );
123 GC_THREAD(ref, refptr, start, end);
129 /* walk through the references of an Object */
130 FOREACH_OBJECT_REF(o,ref,refptr,
132 GC_LOG2( printf("\tobject-field points to %p\n", (void *) ref); );
134 GC_THREAD(ref, refptr, start, end);
142 /* compact_unthread_references *************************************************
144 Unthreads all the references which previousely pointed to an object. The
145 object itself is the head of the threading chain. All the references in the
146 chain once pointed to the object and will point to it's new location
150 o.......Head of the threading chain
151 new.....New Location of the object after compaction
153 *******************************************************************************/
155 static void compact_unthread_references(java_object_t *o, void *new)
157 java_object_t **refptr;
160 GC_LOG2( printf("unthreading in ...\n"); );
162 /* some quick sanity checks */
164 GC_ASSERT(GC_IS_THREADED(o->vftbl));
166 /* walk down the threaded chain */
167 refptr = (java_object_t **) (ptrint) o->vftbl;
168 while (GC_IS_THREADED(refptr)) {
170 /* remove the threading bit */
171 refptr = (java_object_t **) GC_REMOVE_THREAD_BIT(refptr);
173 GC_LOG2( printf("\treference at %p\n", (void *) refptr); );
175 /* update the reference in the chain */
176 tmp = (ptrint) *refptr;
177 *refptr = (java_object_t *) (ptrint) new;
179 /* skip to the next chain value */
180 refptr = (java_object_t **) tmp;
184 /* finally restore the original vftbl pointer */
185 o->vftbl = (struct _vftbl *) refptr;
188 GC_LOG2( printf("\t... pointed to "); heap_print_object(o); printf("\n"); );
189 GC_LOG2( printf("\t... now points to %p\n", (void *) new); );
194 /* compact_move ****************************************************************
196 Moves the content (including header) of an object around in memory
198 NOTE: Memory locations may overlap!
199 NOTE: The size of the object can change by moving it around (hashcode)!
202 old......Old Location of the object before compaction
203 new......New Location of the object after compaction
204 size.....Size of the object in bytes
207 New size of the object after moving it
209 *******************************************************************************/
211 static u4 compact_move(u1 *old, u1 *new, u4 size)
216 GC_ASSERT(new <= old);
218 /* check if locations overlap */
219 if (new + size < old) {
220 /* overlapping: NO */
222 /* copy old object content to new location */
223 MCOPY(new, old, u1, size);
225 #if defined(ENABLE_MEMCHECK)
226 /* invalidate old object */
227 MSET(old, MEMORY_CLEAR_BYTE, u1, size);
231 /* overlapping: YES */
233 GC_LOG2( printf("\tcompact_move(old=%p, new=%p, size=0x%x) overlapps!", old, new, size) );
235 /* copy old object content to new location */
236 MMOVE(new, old, u1, size);
242 /* check if we need to attach the hashcode to the object */
243 if (GC_TEST_FLAGS((java_object_t *) new, HDRFLAG_HASH_TAKEN)) {
245 /* TODO: move this whole bunch to heap_attach_hashcode() */
247 /* change the flags accordingly */
248 GC_CLEAR_FLAGS((java_object_t *) new, HDRFLAG_HASH_TAKEN);
249 GC_SET_FLAGS((java_object_t *) new, HDRFLAG_HASH_ATTACHED);
251 /* attach the hashcode at the end of the object */
252 new_size += SIZEOF_VOID_P;
253 hashcode = (s4) (ptrint) old;
254 *( (s4 *) (new + new_size - SIZEOF_VOID_P) ) = hashcode; /* TODO: clean this up */
256 GC_ASSERT(new + SIZEOF_VOID_P < old);
257 GC_LOG2( dolog("GC: Hash attached: %d (0x%08x) to new object at %p", hashcode, hashcode, new); );
265 /* compact_me ******************************************************************
267 This function actually does the compaction in two passes. Look at the source
268 for further details about the passes.
271 rs.........Rootset, needed to update the root references
272 region.....Region to be compacted
274 *******************************************************************************/
276 void compact_me(rootset_t *rs, regioninfo_t *region)
285 GC_LOG( dolog("GC: Compaction Phase 0 started ..."); );
288 * - thread all references in the rootset */
289 compact_thread_rootset(rs, region->base, region->ptr);
291 GC_LOG( dolog("GC: Compaction Phase 1 started ..."); );
295 * - thread all references
296 * - update forward references */
297 ptr = region->base; ptr_new = region->base;
298 while (ptr < region->ptr) {
299 o = (java_object_t *) ptr;
301 /* uncollectable items should never be compacted */
302 GC_ASSERT(!GC_TEST_FLAGS(o, HDRFLAG_UNCOLLECTABLE));
304 /* if this object is already part of a threaded chain ... */
305 if (GC_IS_THREADED(o->vftbl)) {
307 /* ... unthread the reference chain */
308 compact_unthread_references(o, ptr_new);
312 /* get the object size (objectheader is now unthreaded) */
313 o_size = get_object_size(o);
315 /* only marked objects survive */
316 if (GC_IS_MARKED(o)) {
318 #if defined(GCCONF_HDRFLAG_REFERENCING)
319 /* check if this objects contains references */
320 if (GC_TEST_FLAGS(o, HDRFLAG_REFERENCING))
323 /* thread all the references in this object */
324 compact_thread_references(o, region->base, region->ptr);
326 /* object survives, place next object behind it */
329 /* size might change because of attached hashcode */
330 if (GC_TEST_FLAGS(o, HDRFLAG_HASH_TAKEN))
331 ptr_new += SIZEOF_VOID_P;
334 /* skip to next object */
338 GC_LOG( dolog("GC: Compaction Phase 2 started ..."); );
341 * - scan the heap again
342 * - update backward references
343 * - move the objects */
345 ptr = region->base; ptr_new = region->base;
346 while (ptr < region->ptr) {
347 o = (java_object_t *) ptr;
349 /* if this object is still part of a threaded chain ... */
350 if (GC_IS_THREADED(o->vftbl)) {
352 /* ... unthread the reference chain */
353 compact_unthread_references(o, ptr_new);
357 /* get the object size (objectheader is now unthreaded) */
358 o_size = get_object_size(o);
360 /* move the surviving objects */
361 if (GC_IS_MARKED(o)) {
363 GC_LOG2( printf("moving: %08x -> %08x (%d bytes)\n",
364 (ptrint) ptr, (ptrint) ptr_new, o_size); );
366 /* unmark the object */
369 /* move the object (size can change) */
370 o_size_new = compact_move(ptr, ptr_new, o_size);
372 /* object survives, place next object behind it */
373 ptr_new += o_size_new;
377 /* skip to next object */
381 GC_LOG( dolog("GC: Compaction finished."); );
383 GC_LOG( printf("Region-Used: %d -> %d\n", region->size - region->free, used); )
384 GC_LOG( printf("Region-Free: %d -> %d\n", region->free, region->size - used); )
386 /* update the region information */
387 region->ptr = ptr_new;
388 region->free = region->size - used;
394 * These are local overrides for various environment variables in Emacs.
395 * Please do not remove this and leave it at the end of the file, where
396 * Emacs will automagically detect them.
397 * ---------------------------------------------------------------------
400 * indent-tabs-mode: t
404 * vim:noexpandtab:sw=4:ts=4: