some gc works

This commit is contained in:
hyung-hwan 2020-03-20 09:50:32 +00:00
parent adcbf748a2
commit f0c1a26ccc
4 changed files with 142 additions and 103 deletions

View File

@ -48,7 +48,7 @@ typedef struct hawk_tree_t hawk_tree_t;
#include "err-prv.h" #include "err-prv.h"
#include "misc-prv.h" #include "misc-prv.h"
//#define HAWK_ENABLE_GC /*#define HAWK_ENABLE_GC*/
#define HAWK_ENABLE_STR_CACHE #define HAWK_ENABLE_STR_CACHE
#define HAWK_ENABLE_MBS_CACHE #define HAWK_ENABLE_MBS_CACHE
@ -395,8 +395,8 @@ struct hawk_rtx_t
{ {
int collecting; int collecting;
hawk_oow_t all_count; hawk_oow_t all_count;
hawk_gci_t all; /* allocated objects */ hawk_gch_t all; /* allocated objects */
hawk_gci_t saved; /* objects to preserve */ hawk_gch_t saved; /* objects to preserve */
} gc; } gc;
hawk_nde_blk_t* active_block; hawk_nde_blk_t* active_block;

View File

@ -129,29 +129,29 @@ struct hawk_rtx_alt_t
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
typedef struct hawk_gci_t hawk_gci_t; typedef struct hawk_gch_t hawk_gch_t;
struct hawk_gci_t struct hawk_gch_t
{ {
hawk_gci_t* gc_prev; hawk_gch_t* gc_prev;
hawk_gci_t* gc_next; hawk_gch_t* gc_next;
hawk_uintptr_t gc_refs; hawk_uintptr_t gc_refs;
}; };
#if defined(HAWK_HAVE_INLINE) #if defined(HAWK_HAVE_INLINE)
static HAWK_INLINE hawk_val_t* hawk_gci_to_val(hawk_gci_t* gci) static HAWK_INLINE hawk_val_t* hawk_gch_to_val(hawk_gch_t* gch)
{ {
return (hawk_val_t*)(gci + 1); return (hawk_val_t*)(gch + 1);
} }
static HAWK_INLINE hawk_gci_t* hawk_val_to_gci(hawk_val_t* v) static HAWK_INLINE hawk_gch_t* hawk_val_to_gch(hawk_val_t* v)
{ {
return ((hawk_gci_t*)v) - 1; return ((hawk_gch_t*)v) - 1;
} }
#else #else
# define hawk_val_to_gci(v) (((hawk_gci_t*)(v)) - 1) # define hawk_val_to_gch(v) (((hawk_gch_t*)(v)) - 1)
# define hawk_gci_to_val(gci) ((hawk_val_t*)(((hawk_gci_t*)(gci)) + 1)) # define hawk_gch_to_val(gch) ((hawk_val_t*)(((hawk_gch_t*)(gch)) + 1))
#endif #endif
/** /**

View File

@ -3599,12 +3599,14 @@ static hawk_val_t* do_assignment (hawk_rtx_t* rtx, hawk_nde_t* var, hawk_val_t*
case HAWK_NDE_GBLIDX: case HAWK_NDE_GBLIDX:
case HAWK_NDE_LCLIDX: case HAWK_NDE_LCLIDX:
case HAWK_NDE_ARGIDX: case HAWK_NDE_ARGIDX:
#if !defined(HAWK_ENABLE_GC)
if (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_MAP) if (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_MAP)
{ {
/* a map cannot become a member of a map */ /* a map cannot become a member of a map */
errnum = HAWK_EMAPTOIDX; errnum = HAWK_EMAPTOIDX;
goto exit_on_error; goto exit_on_error;
} }
#endif
ret = do_assignment_idx(rtx, (hawk_nde_var_t*)var, val); ret = do_assignment_idx(rtx, (hawk_nde_var_t*)var, val);
break; break;
@ -3666,7 +3668,6 @@ static hawk_val_t* do_assignment_nonidx (hawk_rtx_t* rtx, hawk_nde_var_t* var, h
hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOSCALAR, HAWK_T("not allowed to change a map '%.*js' to a scalar"), var->id.name.len, var->id.name.ptr); hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOSCALAR, HAWK_T("not allowed to change a map '%.*js' to a scalar"), var->id.name.len, var->id.name.ptr);
return HAWK_NULL; return HAWK_NULL;
} }
#if !defined(HAWK_ENABLE_GC)
else if (vtype == HAWK_VAL_MAP) else if (vtype == HAWK_VAL_MAP)
{ {
/* old value is not a map but a new value is a map. /* old value is not a map but a new value is a map.
@ -3674,7 +3675,6 @@ static hawk_val_t* do_assignment_nonidx (hawk_rtx_t* rtx, hawk_nde_var_t* var, h
hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOVAR, HAWK_T("not allowed to assign a map to a variable '%.*js'"), var->id.name.len, var->id.name.ptr); hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOVAR, HAWK_T("not allowed to assign a map to a variable '%.*js'"), var->id.name.len, var->id.name.ptr);
return HAWK_NULL; return HAWK_NULL;
} }
#endif
} }
if (hawk_htb_upsert(rtx->named, var->id.name.ptr, var->id.name.len, val, 0) == HAWK_NULL) if (hawk_htb_upsert(rtx->named, var->id.name.ptr, var->id.name.len, val, 0) == HAWK_NULL)
@ -3712,7 +3712,6 @@ static hawk_val_t* do_assignment_nonidx (hawk_rtx_t* rtx, hawk_nde_var_t* var, h
hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOSCALAR, HAWK_T("not allowed to change a map '%.*js' to a scalar"), var->id.name.len, var->id.name.ptr); hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOSCALAR, HAWK_T("not allowed to change a map '%.*js' to a scalar"), var->id.name.len, var->id.name.ptr);
return HAWK_NULL; return HAWK_NULL;
} }
#if !defined(HAWK_ENABLE_GC)
else if (vtype == HAWK_VAL_MAP) else if (vtype == HAWK_VAL_MAP)
{ {
/* old value is not a map but a new value is a map. /* old value is not a map but a new value is a map.
@ -3720,7 +3719,6 @@ static hawk_val_t* do_assignment_nonidx (hawk_rtx_t* rtx, hawk_nde_var_t* var, h
hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOVAR, HAWK_T("not allowed to assign a map to a variable '%.*js'"), var->id.name.len, var->id.name.ptr); hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOVAR, HAWK_T("not allowed to assign a map to a variable '%.*js'"), var->id.name.len, var->id.name.ptr);
return HAWK_NULL; return HAWK_NULL;
} }
#endif
} }
hawk_rtx_refdownval (rtx, old); hawk_rtx_refdownval (rtx, old);
@ -3744,7 +3742,6 @@ static hawk_val_t* do_assignment_nonidx (hawk_rtx_t* rtx, hawk_nde_var_t* var, h
hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOSCALAR, HAWK_T("not allowed to change a map '%.*js' to a scalar"), var->id.name.len, var->id.name.ptr); hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOSCALAR, HAWK_T("not allowed to change a map '%.*js' to a scalar"), var->id.name.len, var->id.name.ptr);
return HAWK_NULL; return HAWK_NULL;
} }
#if !defined(HAWK_ENABLE_GC)
else if (vtype == HAWK_VAL_MAP) else if (vtype == HAWK_VAL_MAP)
{ {
/* old value is not a map but a new value is a map. /* old value is not a map but a new value is a map.
@ -3752,7 +3749,6 @@ static hawk_val_t* do_assignment_nonidx (hawk_rtx_t* rtx, hawk_nde_var_t* var, h
hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOVAR, HAWK_T("not allowed to assign a map to a variable '%.*js'"), var->id.name.len, var->id.name.ptr); hawk_rtx_seterrfmt (rtx, &var->loc, HAWK_EMAPTOVAR, HAWK_T("not allowed to assign a map to a variable '%.*js'"), var->id.name.len, var->id.name.ptr);
return HAWK_NULL; return HAWK_NULL;
} }
#endif
} }
hawk_rtx_refdownval (rtx, old); hawk_rtx_refdownval (rtx, old);
@ -3779,7 +3775,9 @@ static hawk_val_t* do_assignment_idx (hawk_rtx_t* rtx, hawk_nde_var_t* var, hawk
var->type == HAWK_NDE_GBLIDX || var->type == HAWK_NDE_GBLIDX ||
var->type == HAWK_NDE_LCLIDX || var->type == HAWK_NDE_LCLIDX ||
var->type == HAWK_NDE_ARGIDX) && var->idx != HAWK_NULL); var->type == HAWK_NDE_ARGIDX) && var->idx != HAWK_NULL);
#if !defined(HAWK_ENABLE_GC)
HAWK_ASSERT (HAWK_RTX_GETVALTYPE (rtx, val) != HAWK_VAL_MAP); HAWK_ASSERT (HAWK_RTX_GETVALTYPE (rtx, val) != HAWK_VAL_MAP);
#endif
retry: retry:
switch (var->type) switch (var->type)

View File

@ -39,65 +39,91 @@ hawk_val_t* hawk_val_zlm = (hawk_val_t*)&awk_zlm;
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
#define GCI_MOVED HAWK_TYPE_MAX(hawk_uintptr_t) #if defined(HAWK_ENABLE_GC)
/*
BEGIN {
@local a, b, nil;
for (i = 1; i < 10; i++) a[i] = i;
a[11] = a;
a[12] = a;
a = nil;
b[1] = a;
c[1] = 0;
} */
#define GCH_MOVED HAWK_TYPE_MAX(hawk_uintptr_t)
static hawk_val_t* gc_calloc (hawk_rtx_t* rtx, hawk_oow_t size) static hawk_val_t* gc_calloc (hawk_rtx_t* rtx, hawk_oow_t size)
{ {
hawk_gci_t* gci; hawk_gch_t* gch;
gci = (hawk_gci_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*gci) + size); gch = (hawk_gch_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*gch) + size);
if (HAWK_UNLIKELY(!gci)) return HAWK_NULL; if (HAWK_UNLIKELY(!gch)) return HAWK_NULL;
return hawk_gci_to_val(gci); return hawk_gch_to_val(gch);
} }
static HAWK_INLINE void gc_chain_gci (hawk_gci_t* list, hawk_gci_t* gci) static HAWK_INLINE void gc_chain_gch (hawk_gch_t* list, hawk_gch_t* gch)
{ {
gci->gc_next = list; gch->gc_next = list;
gci->gc_prev = list->gc_prev; gch->gc_prev = list->gc_prev;
gci->gc_prev->gc_next = gci; gch->gc_prev->gc_next = gch;
list->gc_prev = gci; list->gc_prev = gch;
} }
static HAWK_INLINE void gc_chain_val (hawk_gci_t* list, hawk_val_t* v) static HAWK_INLINE void gc_chain_val (hawk_gch_t* list, hawk_val_t* v)
{ {
gc_chain_gci (list, hawk_val_to_gci(v)); gc_chain_gch (list, hawk_val_to_gch(v));
} }
static HAWK_INLINE void gc_unchain_gci (hawk_gci_t* gci) static HAWK_INLINE void gc_move_gchs (hawk_gch_t* list, hawk_gch_t* src)
{ {
gci->gc_prev->gc_next = gci->gc_next; if (list->gc_next != list)
gci->gc_next->gc_prev = gci->gc_prev; {
hawk_gch_t* last;
last = list->gc_prev;
last->gc_next = src->gc_next;
last->gc_next->gc_prev = last;
list->gc_prev = src->gc_prev;
list->gc_prev->gc_next = list;
}
src->gc_prev = src;
src->gc_next = src;
}
static HAWK_INLINE void gc_unchain_gch (hawk_gch_t* gch)
{
gch->gc_prev->gc_next = gch->gc_next;
gch->gc_next->gc_prev = gch->gc_prev;
} }
static HAWK_INLINE void gc_unchain_val (hawk_val_t* v) static HAWK_INLINE void gc_unchain_val (hawk_val_t* v)
{ {
gc_unchain_gci (hawk_val_to_gci(v)); gc_unchain_gch (hawk_val_to_gch(v));
} }
static void gc_clone_refs (hawk_gci_t* list) static void gc_trace_refs (hawk_gch_t* list)
{ {
hawk_gci_t* gci; hawk_gch_t* gch;
gci = list->gc_next;
while (gci != list)
{
gci->gc_refs = hawk_gci_to_val(gci)->v_refs;
gci = gci->gc_next;
}
}
static void gc_trace_refs (hawk_gci_t* list)
{
hawk_gci_t* gci;
hawk_val_t* v, * iv; hawk_val_t* v, * iv;
hawk_map_itr_t itr; hawk_map_itr_t itr;
hawk_map_pair_t* pair; hawk_map_pair_t* pair;
gci = list->gc_next; /* phase 1 - copy the reference count field from the value header to the gc header */
while (gci != list) gch = list->gc_next;
while (gch != list)
{ {
v = hawk_gci_to_val(gci); gch->gc_refs = hawk_gch_to_val(gch)->v_refs;
gch = gch->gc_next;
}
/* phase 2 - decrement the reference count in the gc header whenever a reference is found */
gch = list->gc_next;
while (gch != list)
{
v = hawk_gch_to_val(gch);
/* as of now, there is only one type available - HAWK_VAL_MAP */ /* as of now, there is only one type available - HAWK_VAL_MAP */
HAWK_ASSERT (v->v_type == HAWK_VAL_MAP); HAWK_ASSERT (v->v_type == HAWK_VAL_MAP);
@ -108,58 +134,52 @@ static void gc_trace_refs (hawk_gci_t* list)
iv = (hawk_val_t*)HAWK_MAP_VPTR(pair); iv = (hawk_val_t*)HAWK_MAP_VPTR(pair);
if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc)
{ {
printf ("decrementing...\n"); hawk_val_to_gch(iv)->gc_refs--;
hawk_val_to_gci(iv)->gc_refs--;
} }
pair = hawk_map_getnextpair(((hawk_val_map_t*)v)->map, &itr); pair = hawk_map_getnextpair(((hawk_val_map_t*)v)->map, &itr);
} }
gci = gci->gc_next; gch = gch->gc_next;
} }
} }
static void gc_dump_refs (hawk_rtx_t* rtx, hawk_gci_t* list) static void gc_dump_refs (hawk_rtx_t* rtx, hawk_gch_t* list)
{ {
hawk_gci_t* gci; hawk_gch_t* gch;
gci = list->gc_next; gch = list->gc_next;
while (gci != list) while (gch != list)
{ {
printf (" %p %d\n", gci, (int)gci->gc_refs); printf (" %p %d\n", gch, (int)gch->gc_refs);
gci = gci->gc_next; gch = gch->gc_next;
} }
printf ("-----all_count => %d---------\n\n", (int)rtx->gc.all_count); printf ("-----all_count => %d---------\n\n", (int)rtx->gc.all_count);
} }
static void gc_move_roots (hawk_gci_t* list, hawk_gci_t* reachable_list) static void gc_move_reachables (hawk_gch_t* list, hawk_gch_t* reachable_list)
{ {
hawk_gci_t* gci, * next; hawk_gch_t* gch, * tmp;
gci = list->gc_next;
while (gci != list)
{
next = gci->gc_next;
if (gci->gc_refs > 0)
{
gc_unchain_gci (gci);
gc_chain_gci (reachable_list, gci);
gci->gc_refs = GCI_MOVED;
}
gci = next;
}
}
static void gc_move_reachables_from_root (hawk_gci_t* reachable_list)
{
hawk_gci_t* gci, * igci;
hawk_val_t* v, * iv; hawk_val_t* v, * iv;
hawk_map_itr_t itr; hawk_map_itr_t itr;
hawk_map_pair_t* pair; hawk_map_pair_t* pair;
gci = reachable_list->gc_next; gch = list->gc_next;
while (gci != reachable_list) while (gch != list)
{ {
v = hawk_gci_to_val(gci); tmp = gch->gc_next;
if (gch->gc_refs > 0)
{
gc_unchain_gch (gch);
gc_chain_gch (reachable_list, gch);
gch->gc_refs = GCH_MOVED;
}
gch = tmp;
}
gch = reachable_list->gc_next;
while (gch != reachable_list)
{
v = hawk_gch_to_val(gch);
/* as of now, there is only one type available - HAWK_VAL_MAP */ /* as of now, there is only one type available - HAWK_VAL_MAP */
/* the key part is a string. don't care. but if a generic value is allowed as a key, this should change... */ /* the key part is a string. don't care. but if a generic value is allowed as a key, this should change... */
@ -171,42 +191,58 @@ static void gc_move_reachables_from_root (hawk_gci_t* reachable_list)
iv = (hawk_val_t*)HAWK_MAP_VPTR(pair); iv = (hawk_val_t*)HAWK_MAP_VPTR(pair);
if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc)
{ {
igci = hawk_val_to_gci(iv); tmp = hawk_val_to_gch(iv);
if (igci->gc_refs != GCI_MOVED) if (tmp->gc_refs != GCH_MOVED)
{ {
gc_unchain_gci (igci); gc_unchain_gch (tmp);
gc_chain_gci (reachable_list, igci); gc_chain_gch (reachable_list, tmp);
igci->gc_refs = GCI_MOVED; tmp->gc_refs = GCH_MOVED;
} }
} }
pair = hawk_map_getnextpair(((hawk_val_map_t*)v)->map, &itr); pair = hawk_map_getnextpair(((hawk_val_map_t*)v)->map, &itr);
} }
gci = gci->gc_next; gch = gch->gc_next;
}
}
static void gc_free_unreachables (hawk_rtx_t* rtx, hawk_gch_t* list)
{
hawk_gch_t* gch, * tmp;
gch = list->gc_next;
while (gch != list)
{
tmp = gch->gc_next;
printf ("^^^^^^^^^^^^^^^^^^^^^^^^ freeing %p(%p) gc_refs %d v_refs %d\n", gch, gch->gc_refs, hawk_gch_to_val(gch)->v_refs);
hawk_rtx_freeval (rtx, hawk_gch_to_val(gch), 0);
gch = tmp;
} }
} }
void gc_collect_garbage (hawk_rtx_t* rtx) void gc_collect_garbage (hawk_rtx_t* rtx)
{ {
hawk_gci_t reachable; hawk_gch_t reachable;
gc_clone_refs (&rtx->gc.all); printf ("collecting garbage...\n");
gc_trace_refs (&rtx->gc.all); gc_trace_refs (&rtx->gc.all);
gc_dump_refs (rtx, &rtx->gc.all); reachable.gc_prev = &reachable;
/*reachable.gc_prev = &reachable;
reachable.gc_next = &reachable; reachable.gc_next = &reachable;
gc_move_roots (&rtx->gc.all, &reachable);*/ gc_move_reachables (&rtx->gc.all, &reachable);
/*
gc_move_reachables_from_root (&reachable, &reachable);
/* only unreachables are left in rtx->gc.all */
gc_dump_refs (rtx, &rtx->gc.all);
gc_free_unreachables (rtx, &rtx->gc.all);
HAWK_ASSERT (rtx->gc.all.gc_next == &rtx->gc.all);
destroy_all_in_ rtx->gc.all gc_move_gchs (&rtx->gc.all, &reachable);
move_reachable_back_to rtx->gc.all???*/
printf ("collecting garbage.done ..\n");
} }
#endif
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
hawk_val_t* hawk_get_awk_nil_val (void) hawk_val_t* hawk_get_awk_nil_val (void)
@ -694,6 +730,11 @@ static void free_mapval (hawk_map_t* map, void* dptr, hawk_oow_t dlen)
hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("refdown in map free - [%O]\n"), dptr); hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_T("refdown in map free - [%O]\n"), dptr);
#endif #endif
#if defined(HAWK_ENABLE_GC)
/* this part is not right i think.... revisit this ... */
if (HAWK_RTX_GETVALTYPE(rtx, (hawk_val_t*)dptr) == HAWK_VAL_MAP &&
((hawk_val_map_t*)dptr)->map == map) return;
#endif
hawk_rtx_refdownval (rtx, dptr); hawk_rtx_refdownval (rtx, dptr);
} }
@ -1055,7 +1096,7 @@ void hawk_rtx_freeval (hawk_rtx_t* rtx, hawk_val_t* val, int cache)
/* don't free ptr as it is inlined to val /* don't free ptr as it is inlined to val
hawk_rtx_freemem (rtx, ((hawk_val_rex_t*)val)->ptr); hawk_rtx_freemem (rtx, ((hawk_val_rex_t*)val)->ptr);
*/ */
/* code is just a pointer to a regular expression stored /* code is just a pointer to a regular expression stored
* in parse tree nodes. so don't free it. * in parse tree nodes. so don't free it.
hawk_freerex (rtx->hawk, ((hawk_val_rex_t*)val)->code[0], ((hawk_val_rex_t*)val)->code[1]); hawk_freerex (rtx->hawk, ((hawk_val_rex_t*)val)->code[0], ((hawk_val_rex_t*)val)->code[1]);
@ -1074,7 +1115,7 @@ void hawk_rtx_freeval (hawk_rtx_t* rtx, hawk_val_t* val, int cache)
rtx->gc.all_count--; rtx->gc.all_count--;
gc_unchain_val (val); gc_unchain_val (val);
hawk_map_fini (((hawk_val_map_t*)val)->map); hawk_map_fini (((hawk_val_map_t*)val)->map);
hawk_rtx_freemem (rtx, hawk_val_to_gci(val)); hawk_rtx_freemem (rtx, hawk_val_to_gch(val));
#else #else
hawk_map_fini (((hawk_val_map_t*)val)->map); hawk_map_fini (((hawk_val_map_t*)val)->map);
hawk_rtx_freemem (rtx, val); hawk_rtx_freemem (rtx, val);