diff --git a/include/QF/object.h b/include/QF/object.h index a772faf9a..d208cb69f 100644 --- a/include/QF/object.h +++ b/include/QF/object.h @@ -74,12 +74,14 @@ struct List_s; typedef void (*ReplyHandler_t) (struct Object_s *retValue); typedef struct Object_s { + unsigned marked :1; + unsigned finalized :1; struct Class_s *cl; int refs; - qboolean marked; struct Object_s *next; struct String_s * methodDecl(Object, toString); ObjRefs_t * methodDecl(Object, allRefs); + qboolean methodDecl(Object, finalize); void *data; } Object; diff --git a/include/garbage.h b/include/garbage.h index d5365d889..af68e5827 100644 --- a/include/garbage.h +++ b/include/garbage.h @@ -33,8 +33,8 @@ #define __garbage_h void Garbage_Do_Mark (Object *root); -void Garbage_Do_Sweep (Object **allobjs); +Object * Garbage_Do_Sweep (Object **allobjs); unsigned int Garbage_Pending (void); -void Garbage_Dispose (unsigned int amount); +void Garbage_Dispose (Object **allobjs, unsigned int amount); #endif diff --git a/libs/object/garbage.c b/libs/object/garbage.c index 7d97df3db..71d5d66d8 100644 --- a/libs/object/garbage.c +++ b/libs/object/garbage.c @@ -61,24 +61,32 @@ Garbage_Do_Mark (Object *root) } } -void +Object * Garbage_Do_Sweep (Object **allobjs) { Object **prevNext; Object *obj; - for (prevNext = allobjs, obj = *allobjs; obj; obj = *prevNext) { + for (prevNext = allobjs, obj = *allobjs;; obj = *prevNext) { if (obj->marked) { obj->marked = false; prevNext = &obj->next; } else if (!obj->refs) { - *prevNext = obj->next; - obj->next = junk; - junk = obj; - junked++; - Sys_DPrintf ("GC: %s@%p is ready for disposal...\n", obj->cl->name, obj); + if (!obj->finalized && methodCall(obj, finalize)) { + obj->finalized = true; + Garbage_Do_Mark (obj); + prevNext = &obj->next; + } else { + *prevNext = obj->next; + obj->next = junk; + junk = obj; + junked++; + Sys_DPrintf ("GC: %s@%p is ready for disposal...\n", obj->cl->name, obj); + } } else *prevNext = obj->next; + if (!*prevNext) + return obj; } } @@ -89,14 +97,20 @@ Garbage_Pending (void) } void -Garbage_Dispose (unsigned int amount) +Garbage_Dispose (Object **allobjs, unsigned int amount) { Object *next; for (; junk && amount; junk = next, amount--) { next = junk->next; - Sys_DPrintf ("GC: Disposing of %s@%p...\n", junk->cl->name, junk); - Object_Delete (junk); - junked--; + if (junk->marked) { + junk->marked = false; + junk->next = *allobjs; + *allobjs = junk; + } else { + Sys_DPrintf ("GC: Disposing of %s@%p...\n", junk->cl->name, junk); + Object_Delete (junk); + junked--; + } } } diff --git a/libs/object/object.c b/libs/object/object.c index afba4bca3..b09745a6e 100644 --- a/libs/object/object.c +++ b/libs/object/object.c @@ -61,6 +61,12 @@ static __attribute__ ((unused)) const char rcsid[] = Object *allObjs = NULL; ArrayList *rootObj = NULL; +static qboolean +Object_Finalize_f (Object *self) +{ + return false; +} + static String * Object_ToString_f (Object *self) { @@ -72,6 +78,7 @@ Object_Init_f (Object *self) { self->allRefs = NULL; self->toString = Object_ToString_f; + self->finalize = Object_Finalize_f; Sys_DPrintf("%s@%p initing...\n", self->cl->name, self); } @@ -117,6 +124,7 @@ Object_Create (Class *cl, qboolean floating) } else new->refs = 1; new->marked = false; + new->finalized = false; new->next = allObjs; allObjs = new; return new; @@ -243,13 +251,18 @@ Object_Garbage_Collect (void) frames++; if (frames % 2000 == 0) { + Object *all, *last; Sys_DPrintf("GC: Marking...\n"); Garbage_Do_Mark (OBJECT(rootObj)); Sys_DPrintf("GC: Sweeping...\n"); - Garbage_Do_Sweep (&allObjs); + all = allObjs; + allObjs = NULL; + last = Garbage_Do_Sweep (&all); + last->next = allObjs; + allObjs = all; } if (frames % 50 == 0 && Garbage_Pending()) { Sys_DPrintf("GC: Disposing...\n"); - Garbage_Dispose (Garbage_Pending()/2 + 1); + Garbage_Dispose (&allObjs, Garbage_Pending()/2 + 1); } }