--- /dev/null
+/* mm/cacao-gc/compact.c - GC module for compacting heap regions
+
+ Copyright (C) 2006 R. Grafl, A. Krall, C. Kruegel,
+ C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+ E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+ J. Wenninger, Institut f. Computersprachen - TU Wien
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Contact: cacao@cacaojvm.org
+
+ Authors: Michael Starzinger
+
+ $Id$
+
+*/
+
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "gc.h"
+#include "heap.h"
+#include "mark.h"
+#include "mm/memory.h"
+#include "toolbox/logging.h"
+
+
+/* Threading macros ***********************************************************/
+
+#define GC_THREAD_BIT 0x01
+
+#define GC_IS_THREADED(ptr) (((ptrint) ptr) & GC_THREAD_BIT)
+#define GC_REMOVE_THREAD_BIT(ptr) (((ptrint) ptr) & ~GC_THREAD_BIT)
+#define GC_SET_THREAD_BIT(ptr) (((ptrint) ptr) | GC_THREAD_BIT)
+
+#define GC_THREAD(ref, refptr, start, end) \
+ if (POINTS_INTO(ref, start, end)) { \
+ GC_ASSERT(GC_IS_MARKED(ref)); \
+ *refptr = (java_objectheader *) ref->vftbl; \
+ ref->vftbl = (struct _vftbl *) GC_SET_THREAD_BIT(refptr); \
+ }
+
+
+/* compact_thread_rootset ******************************************************
+
+ Threads all the references in the rootset
+
+ IN:
+ rs........Rootset containing the references to be threaded.
+ start.....Region to be compacted start here
+ end.......Region to be compacted ends here
+
+*******************************************************************************/
+
+void compact_thread_rootset(rootset_t *rs, void *start, void *end)
+{
+ java_objectheader *ref;
+ java_objectheader **refptr;
+ int i;
+
+ GC_LOG( printf("threading in rootset\n"); );
+
+ /* walk through the references of this rootset */
+ for (i = 0; i < rs->refcount; i++) {
+
+ /* load the reference */
+ refptr = rs->refs[i];
+ ref = *( refptr );
+
+ GC_LOG( printf("\troot pointer to %p\n", (void *) ref); );
+
+ /* thread the references */
+ GC_THREAD(ref, refptr, start, end);
+
+ }
+}
+
+
+/* compact_thread_references ***************************************************
+
+ Threads all the references of an object.
+
+ IN:
+ o.........Object containing the references to be threaded.
+ start.....Region to be compacted start here
+ end.......Region to be compacted ends here
+
+*******************************************************************************/
+
+void compact_thread_references(java_objectheader *o, void *start, void *end)
+{
+ java_objectheader *ref;
+ java_objectheader **refptr;
+
+ GC_LOG( printf("threading in ");
+ heap_print_object(o); printf("\n"); );
+
+ if (IS_ARRAY(o)) {
+
+ /* walk through the references of an Array */
+ FOREACH_ARRAY_REF(o,ref,refptr,
+
+ GC_LOG( printf("\tarray-entry points to %p\n", (void *) ref); );
+
+ GC_THREAD(ref, refptr, start, end);
+
+ );
+
+ } else {
+
+ /* walk through the references of an Object */
+ FOREACH_OBJECT_REF(o,ref,refptr,
+
+ GC_LOG( printf("\tobject-field points to %p\n", (void *) ref); );
+
+ GC_THREAD(ref, refptr, start, end);
+
+ );
+
+ }
+}
+
+
+/* compact_unthread_references *************************************************
+
+ Unthreads all the references which previousely pointed to an object. The
+ object itself is the head of the threading chain. All the references in the
+ chain once pointed to the object and will point to it's new location
+ afterwards.
+
+ IN:
+ o.......Head of the threading chain
+ new.....New Location of the object after compaction
+
+*******************************************************************************/
+
+void compact_unthread_references(java_objectheader *o, void *new)
+{
+ java_objectheader **refptr;
+ ptrint tmp;
+
+ GC_LOG( printf("unthreading in ...\n"); );
+
+ /* some quick sanity checks */
+ GC_ASSERT(o);
+ GC_ASSERT(GC_IS_THREADED(o->vftbl));
+
+ /* walk down the threaded chain */
+ refptr = (java_objectheader **) (ptrint) o->vftbl;
+ while (GC_IS_THREADED(refptr)) {
+
+ /* remove the threading bit */
+ refptr = (java_objectheader **) GC_REMOVE_THREAD_BIT(refptr);
+
+ GC_LOG( printf("\treference at %p\n", (void *) refptr); );
+
+ /* update the reference in the chain */
+ tmp = (ptrint) *refptr;
+ *refptr = (java_objectheader *) (ptrint) new;
+
+ /* skip to the next chain value */
+ refptr = (java_objectheader **) tmp;
+
+ }
+
+ /* finally restore the original vftbl pointer */
+ o->vftbl = (struct _vftbl *) refptr;
+ GC_ASSERT(o->vftbl);
+
+ GC_LOG( printf("\t... pointed to "); heap_print_object(o); printf("\n"); );
+ GC_LOG( printf("\t... now points to %p\n", (void *) new); );
+
+}
+
+
+/* compact_move ****************************************************************
+
+ Moves the content (including header) of an object around in memory
+
+ NOTE: Memory locations may overlap!
+
+ IN:
+ old......Old Location of the object before compaction
+ new......New Location of the object after compaction
+ size.....Size of the object in bytes
+
+*******************************************************************************/
+
+void compact_move(void *old, void *new, u4 size)
+{
+ /* copy old object content to new location */
+ /* TODO: maybe we can use memcpy here!!! */
+ MMOVE(new, old, u1, size);
+
+ /* invalidate old object */
+ /* TODO: this only works for non-overlaping */
+ MSET(old, 0x44, u1, size);
+}
+
+
+/* compact_me ******************************************************************
+
+ This function actually does the compaction in two passes. Look at the source
+ for further details about the passes.
+
+ IN:
+ rs........Rootset, needed to update the root references
+ start.....Region to be compacted start here
+ end.......Region to be compacted ends here
+
+*******************************************************************************/
+
+void compact_me(rootset_t *rs, void *start, void *end)
+{
+ u1 *ptr;
+ u1 *ptr_new;
+ java_objectheader *o;
+ u4 o_size;
+
+ GC_LOG( dolog("GC: Compaction Phase 1 started ..."); );
+
+ /* Phase 0:
+ * - thread all references in the rootset */
+ compact_thread_rootset(rs, start, end);
+
+ /* Phase 1:
+ * - scan the heap
+ * - thread all references
+ * - update forward references */
+ ptr = start; ptr_new = end;
+ while (ptr < (u1 *) end) {
+ o = (java_objectheader *) ptr;
+
+ /* TODO: uncollectable items should never be compacted, but for now we do it */
+ /*GC_ASSERT(!GC_TEST_FLAGS(o, GC_FLAG_UNCOLLECTABLE));*/
+ /*if (GC_TEST_FLAGS(o, GC_FLAG_UNCOLLECTABLE)) {
+ GC_SET_MARKED(o);
+ }*/
+
+ /* if this object is already part of a threaded chain ... */
+ if (GC_IS_THREADED(o->vftbl)) {
+
+ /* ... unthread the reference chain */
+ compact_unthread_references(o, ptr_new);
+
+ }
+
+ /* get the object size (objectheader is now unthreaded) */
+ o_size = get_object_size(o);
+
+ /* only marked objects survive */
+ if (GC_IS_MARKED(o)) {
+
+ /* thread all the references in this object */
+ compact_thread_references(o, start, end);
+
+ /* object survives, place next object behind it */
+ ptr_new += o_size;
+ }
+
+ /* skip to next object */
+ ptr += o_size;
+ }
+
+ GC_LOG( dolog("GC: Compaction Phase 2 started ..."); );
+
+ /* Phase 2:
+ * - scan the heap again
+ * - update backward references
+ * - move the objects */
+ ptr = start; ptr_new = end;
+ while (ptr < (u1 *) end) {
+ o = (java_objectheader *) ptr;
+
+ /* if this object is still part of a threaded chain ... */
+ if (GC_IS_THREADED(o->vftbl)) {
+
+ /* ... unthread the reference chain */
+ compact_unthread_references(o, ptr_new);
+
+ }
+
+ /* get the object size (objectheader is now unthreaded) */
+ o_size = get_object_size(o);
+
+ /* move the surviving objects */
+ if (GC_IS_MARKED(o)) {
+
+ GC_LOG( printf("moving: %08x -> %08x (%d bytes)\n",
+ (ptrint) ptr, (ptrint) ptr_new, o_size); );
+
+ /* unmark the object */
+ GC_CLEAR_MARKED(o);
+
+ /* move the object */
+ compact_move(ptr, ptr_new, o_size);
+
+ /* object survives, place next object behind it */
+ ptr_new += o_size;
+ }
+
+ /* skip to next object */
+ ptr += o_size;
+ }
+
+ GC_LOG( dolog("GC: Compaction finished."); );
+
+ /* TODO: this is only for debugging */
+ /* TODO: also modify the two initialisations of ptr_new above!!! */
+ heap_ptr = ptr_new;
+ GC_LOG( heap_dump_region(end, ptr_new, false); );
+
+}
+
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */