/* Provides: GC_malloc_weak_array size_weak_array, mark_weak_array, fixup_weak_array init_weak_arrays zero_weak_arrays GC_malloc_weak_box size_weak_box, mark_weak_box, fixup_weak_box init_weak_boxes zero_weak_boxes GC_malloc_ephemeron size_ephemeron, mark_ephemeron, fixup_ephemeron init_ephemerons mark_ready_ephemerons zero_remaining_ephemerons Requires: gc_weak_array_tag weak_box_tag ephemeron_tag is_marked(p) Type_Tag */ /******************************************************************************/ /* weak arrays */ /******************************************************************************/ /* The GC_Weak_Array structure is not externally visible, but clients expect a specific structure. See README for more information. */ typedef struct GC_Weak_Array { Type_Tag type; short keyex; long count; void *replace_val; struct GC_Weak_Array *next; void *data[1]; /* must be the 5th longword! */ } GC_Weak_Array; static GC_Weak_Array *weak_arrays; static int size_weak_array(void *p) { GC_Weak_Array *a = (GC_Weak_Array *)p; return gcBYTES_TO_WORDS(sizeof(GC_Weak_Array) + ((a->count - 1) * sizeof(void *))); } static int mark_weak_array(void *p) { GC_Weak_Array *a = (GC_Weak_Array *)p; gcMARK(a->replace_val); a->next = weak_arrays; weak_arrays = a; #if CHECKS /* For now, weak arrays only used for symbols and falses: */ { void **data; int i; data = a->data; for (i = a->count; i--; ) { if (data[i] && (*(short *)(data[i]) != 46) && (*(short *)(data[i]) != 56)) CRASH(1); } } #endif return gcBYTES_TO_WORDS(sizeof(GC_Weak_Array) + ((a->count - 1) * sizeof(void *))); } static int fixup_weak_array(void *p) { GC_Weak_Array *a = (GC_Weak_Array *)p; int i; void **data; gcFIXUP(a->replace_val); data = a->data; for (i = a->count; i--; ) { if (data[i]) gcFIXUP(data[i]); } return gcBYTES_TO_WORDS(sizeof(GC_Weak_Array) + ((a->count - 1) * sizeof(void *))); } void *GC_malloc_weak_array(size_t size_in_bytes, void *replace_val) { GC_Weak_Array *w; /* Allcation might trigger GC, so we use park: */ park[0] = replace_val; w = (GC_Weak_Array *)GC_malloc_one_tagged(size_in_bytes + sizeof(GC_Weak_Array) - sizeof(void *)); replace_val = park[0]; park[0] = NULL; w->type = gc_weak_array_tag; w->replace_val = replace_val; w->count = (size_in_bytes >> LOG_WORD_SIZE); return w; } void init_weak_arrays() { weak_arrays = NULL; } static void zero_weak_arrays() { GC_Weak_Array *wa; int i; wa = weak_arrays; while (wa) { void **data; data = wa->data; for (i = wa->count; i--; ) { void *p = data[i]; if (p && !is_marked(p)) data[i] = wa->replace_val; } wa = wa->next; } } /******************************************************************************/ /* weak boxes */ /******************************************************************************/ /* The GC_Weak_Box struct is not externally visible, but first three fields are mandated by the GC interface */ typedef struct GC_Weak_Box { Type_Tag type; short keyex; void *val; /* The rest is up to us: */ void **secondary_erase; int soffset; struct GC_Weak_Box *next; } GC_Weak_Box; static GC_Weak_Box *weak_boxes; static int size_weak_box(void *p) { return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box)); } static int mark_weak_box(void *p) { GC_Weak_Box *wb = (GC_Weak_Box *)p; gcMARK(wb->secondary_erase); if (wb->val) { wb->next = weak_boxes; weak_boxes = wb; } return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box)); } static int fixup_weak_box(void *p) { GC_Weak_Box *wb = (GC_Weak_Box *)p; gcFIXUP(wb->secondary_erase); gcFIXUP(wb->val); return gcBYTES_TO_WORDS(sizeof(GC_Weak_Box)); } void *GC_malloc_weak_box(void *p, void **secondary, int soffset) { GC_Weak_Box *w; /* Allcation might trigger GC, so we use park: */ park[0] = p; park[1] = secondary; w = (GC_Weak_Box *)GC_malloc_one_tagged(sizeof(GC_Weak_Box)); p = park[0]; park[0] = NULL; secondary = (void **)park[1]; park[1] = NULL; w->type = weak_box_tag; w->val = p; w->secondary_erase = secondary; w->soffset = soffset; return w; } void init_weak_boxes() { weak_boxes = NULL; } static void zero_weak_boxes() { GC_Weak_Box *wb; wb = weak_boxes; while (wb) { if (!is_marked(wb->val)) { wb->val = NULL; if (wb->secondary_erase) { *(wb->secondary_erase + wb->soffset) = NULL; wb->secondary_erase = NULL; } } wb = wb->next; } } /******************************************************************************/ /* ephemeron */ /******************************************************************************/ /* The GC_Ephemeron struct is not externally visible, but first three fields are mandated by the GC interface */ typedef struct GC_Ephemeron { Type_Tag type; short keyex; void *key; void *val; /* The rest is up to us: */ struct GC_Ephemeron *next; } GC_Ephemeron; static GC_Ephemeron *ephemerons; static int size_ephemeron(void *p) { return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron)); } static int mark_ephemeron(void *p) { GC_Ephemeron *eph = (GC_Ephemeron *)p; if (eph->val) { eph->next = ephemerons; ephemerons = eph; } return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron)); } static int fixup_ephemeron(void *p) { GC_Ephemeron *eph = (GC_Ephemeron *)p; gcFIXUP(eph->key); gcFIXUP(eph->val); return gcBYTES_TO_WORDS(sizeof(GC_Ephemeron)); } void *GC_malloc_ephemeron(void *k, void *v) { GC_Ephemeron *eph; /* Allcation might trigger GC, so we use park: */ park[0] = k; park[1] = v; eph = (GC_Ephemeron *)GC_malloc_one_tagged(sizeof(GC_Ephemeron)); k = park[0]; park[0] = NULL; v = park[1]; park[1] = NULL; eph->type = ephemeron_tag; eph->key = k; eph->val = v; return eph; } void init_ephemerons() { ephemerons = NULL; } static void mark_ready_ephemerons() { GC_Ephemeron *waiting = NULL, *next, *eph; for (eph = ephemerons; eph; eph = next) { next = eph->next; if (is_marked(eph->key)) { gcMARK(eph->val); } else { eph->next = waiting; waiting = eph; } } ephemerons = waiting; } static void zero_remaining_ephemerons() { GC_Ephemeron *eph; /* After unordered finalization, any remaining ephemerons should be zeroed. */ for (eph = ephemerons; eph; eph = eph->next) { eph->key = NULL; eph->val = NULL; } }