/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT * Copyright 1989 Massachusetts Institute of Technology */ /******************************************************\ * * * reference.c: * * reference count management and other storage issues * * * \******************************************************/ #include "EXTERN.h" #include "wool.h" /* * The memory management of WOOL is implemented via a differed reference * count. That, each time an object's reference count attains 0, it is put in * the zrt, which is polled at regular intervals */ /************************************\ * * * Zero_reference table module (zrt) * * * \************************************/ /* * The zrt (Zero Reference Table) global structure is used to mark ALL wobs * that have at any moment be of REF 0, that is either being created or via * decrease_reference. Then you can call zrt_gc at strategic moments, (ie in * no enclosing WOOL function) to free all the zero-referenced objects in the * zrt. */ #ifdef STATS //Er... this is an old-style function definition, right? So why does it have two types? //WOOL_OBJECT void zrtstats(void) { wool_printf("Zero-reference-table has %d", zrt_size); wool_printf("/%d slots\n", zrt_limit); } #endif /* STATS */ void zrt_init(void) { zrt_size = 0; zrt_limit = 63; /* pow(2,n)/4 -1 */ zrt = (WOOL_OBJECT *) Malloc(zrt_limit * sizeof(WOOL_OBJECT)); zrt_last = zrt; } /* * disposes really of objects stacked in zrt. Be warned that a WOOL_free might * trigger zrt_put during the zrt_gc ! */ static int WlZrtInGc = 0; void zrt_gc(int from) { WOOL_OBJECT *zrt_from = zrt + from; WlZrtInGc = 1; while (zrt_last > zrt_from) { zrt_last--, zrt_size--; if (REF(*zrt_last)) { /* ok, graduate to normal object */ (*zrt_last) -> reference_count |= 1; } else { /* free it */ WOOL_send(WOOL_free, *zrt_last, (*zrt_last)); } } WlZrtInGc = 0; } /* * Never call zrt_put if obj was already in it (sould not happen) */ WOOL_OBJECT zrt_put(WOOL_OBJECT obj) { WOOL_OBJECT *old_zrt; #ifdef DEBUG must_not_be_in_zrt(obj); #endif /* DEBUG */ if (WlZrtInGc) { WOOL_send(WOOL_free, obj, (obj)); } else { if(zrt_size == zrt_limit) { zrt_limit = (zrt_limit + 1) * 2 -1; old_zrt = zrt; zrt = (WOOL_OBJECT *) Realloc(zrt, zrt_limit * sizeof(WOOL_OBJECT)); zrt_last = zrt + (zrt_last - old_zrt); } zrt_size ++; obj -> reference_count = 0; return *zrt_last++ = obj; } //I don't think we're supposed to reach here... return NIL; } /* when an object is physically replaced by another, update its entry * in the zrt */ void zrt_replace_element(WOOL_OBJECT old, WOOL_OBJECT new) { WOOL_OBJECT *zrt_ptr = zrt; while (zrt_ptr < zrt_last) { if (*zrt_ptr == old) { *zrt_ptr = new; return; } zrt_ptr++; } #ifdef DEBUG wool_error("replaced object 0x%x was not in zrt!", old); #endif /* DEBUG */ } #ifdef DEBUG /* checks that the element is not in fact already in the zrt... */ void must_not_be_in_zrt(WOOL_OBJECT obj) { WOOL_OBJECT *zrt_ptr = zrt; while (zrt_ptr < zrt_last) { if (*zrt_ptr == obj) { wool_printf("at zrt[%d]", zrt_last - zrt); wool_printf(" and zrt[%d], type: ", zrt_ptr - zrt); wool_print(wool_type(obj)); wool_puts(", obj: "); wool_print(obj); wool_newline(); wool_error("object 0x%x was already in zrt!", obj); } zrt_ptr++; } } #endif /* DEBUG */ /***********************\ * * * reference management * * * \***********************/ /* increase_reference is a macro (REF(x)++) */ #ifdef DEBUG /* macro otherwise */ void increase_reference(WOOL_OBJECT obj) /* obj may be UNDEFINED */ { REF(obj) += 2; } void decrease_reference(WOOL_OBJECT obj) /* obj may be UNDEFINED */ { if (obj) { if (((obj -> reference_count) -= 2) == 1) zrt_put(obj); else if (obj -> reference_count < 0) { wool_print(obj); wool_error(": reference_count became %d", obj -> reference_count); } } } void decrease_reference_non_null(WOOL_OBJECT obj) /* obj must be non-nil */ { if (((obj -> reference_count) -= 2) == 1) zrt_put(obj); else if (obj -> reference_count < 0) { wool_print(obj); wool_error(": reference_count became %d", obj -> reference_count); } } #endif /* DEBUG */ /* * decrease_reference_in_list: * decrease reference count of all the elements of the list. * but doesn't free the list. */ void decrease_reference_in_list(int count, WOOL_OBJECT *list) { WOOL_OBJECT *last = list + count; while (list < last){ decrease_reference(*list); list++; } } /* * duplicate an array of objects, increasing the reference count, * and mallocing */ void duplicate_n_objects(WOOL_OBJECT *source, WOOL_OBJECT **dest, int n) /* source is the array, dest is a POINTER to the array, n is how many to copy */ { WOOL_OBJECT *p = source, *q, *last = source + n; q = *dest = (WOOL_OBJECT *) Malloc(sizeof(WOOL_OBJECT) * n); while (p < last) increase_reference(*q++ = *p++); } /* * duplicate an array of objects, increasing the reference count, * without mallocing (dest already points to an malloced aera) */ void copy_n_objects(WOOL_OBJECT *source, WOOL_OBJECT *dest, int n) /* source is the array */ /* dest is the array */ /* how many to copy */ { WOOL_OBJECT *p = source, *q = dest, *last = source + n; while (p < last) increase_reference(*q++ = *p++); } /************************************\ * * * Delayed Free table module (dft) * * * \************************************/ /* this table holds all memory chunks that should be freed only when at the * top-level */ #define INITIAL_DFT_SIZE 31 /* pow(2,n)/4 - 1 */ /* This table holds memory chunks that are to be freed at the top-level */ void dft_init(void) { dft = (char **) Malloc(INITIAL_DFT_SIZE * sizeof(char *)); dft_last = dft; dft_last_allocated = dft + INITIAL_DFT_SIZE; } /* dft_gc disposes really of memory stacked in dft. Defined as a macro * while (dft_last > dft) Free(*(--dft_last)) in wool.h */ /* put in dft for later freeing */ void DelayedFree(char *ptr) { ASSERT(ptr != NULL); if(dft_last == dft_last_allocated) { char **old_dft; int size = dft_last - dft, old_size = size; size = (size + 1) * 2 -1; old_dft = dft; dft = (char **) Realloc(dft, size * sizeof(char *)); dft_last = dft + old_size; dft_last_allocated = dft + size; } *dft_last++ = ptr; }