racket/src/mzscheme/gc2/weak.c
Matthew Flatt aad0d1e81b 301.6
svn: r2272
2006-02-17 21:23:21 +00:00

327 lines
6.7 KiB
C

/*
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;
}
}