/*
* reclaim.c
* loops through all variables in all objects looking for the possibility
* of freeing up destructed objects (that are still hanging around because
* of references) -- coded by Blackthorn@Genocide Feb. 1993
*/
#include "std.h"
#include "lpc_incl.h"
#include "reclaim.h"
#define MAX_RECURSION 25
static void gc_mapping PROT((mapping_t *));
static void check_svalue PROT((svalue_t *));
static int cleaned, nested;
static void
check_svalue P1(svalue_t *, v)
{
register int idx;
nested++;
if (nested > MAX_RECURSION) {
return;
}
switch (v->type) {
case T_OBJECT:
if (v->u.ob->flags & O_DESTRUCTED) {
free_svalue(v, "reclaim_objects");
*v = const0n;
cleaned++;
}
break;
case T_MAPPING:
gc_mapping(v->u.map);
break;
case T_ARRAY:
for (idx = 0; idx < v->u.arr->size; idx++)
check_svalue(&v->u.arr->item[idx]);
break;
case T_FUNCTION:
{
svalue_t tmp;
tmp.type = T_ARRAY;
if ((tmp.u.arr = v->u.fp->hdr.args))
check_svalue(&tmp);
break;
}
}
nested--;
return;
}
static void
gc_mapping P1(mapping_t *, m)
{
/* Be careful to correctly handle destructed mapping keys. We can't
* just call check_svalue() b/c the hash would be wrong and the '0'
* element we add would be unreferenceable (in most cases)
*/
mapping_node_t **prev, *elt;
int j = (int) m->table_size;
do {
prev = m->table + j;
while ((elt = *prev)) {
if (elt->values[0].type == T_OBJECT) {
if (elt->values[0].u.ob->flags & O_DESTRUCTED) {
/* found one, do a map_delete() */
if (!(*prev = elt->next) && !m->table[j])
m->unfilled++;
cleaned++;
m->count--;
total_mapping_nodes--;
total_mapping_size -= sizeof(mapping_node_t);
free_svalue(elt->values + 1, "gc_mapping");
free_node(elt);
continue;
}
} else {
/* in case the key is a mapping or something */
check_svalue(elt->values);
}
check_svalue(elt->values+1);
prev = &(elt->next);
}
} while (j--);
}
int reclaim_objects()
{
int i;
object_t *ob;
cleaned = nested = 0;
for (ob = obj_list; ob; ob = ob->next_all)
if (ob->prog)
for (i = 0; i < (int) ob->prog->num_variables; i++)
check_svalue(&ob->variables[i]);
return cleaned;
}