diff --git a/hawk/lib/hawk-prv.h b/hawk/lib/hawk-prv.h index ff9359de..0384985a 100644 --- a/hawk/lib/hawk-prv.h +++ b/hawk/lib/hawk-prv.h @@ -48,7 +48,7 @@ typedef struct hawk_tree_t hawk_tree_t; #include "err-prv.h" #include "misc-prv.h" -//#define HAWK_ENABLE_GC +/*#define HAWK_ENABLE_GC*/ #define HAWK_ENABLE_STR_CACHE #define HAWK_ENABLE_MBS_CACHE @@ -395,8 +395,8 @@ struct hawk_rtx_t { int collecting; hawk_oow_t all_count; - hawk_gci_t all; /* allocated objects */ - hawk_gci_t saved; /* objects to preserve */ + hawk_gch_t all; /* allocated objects */ + hawk_gch_t saved; /* objects to preserve */ } gc; hawk_nde_blk_t* active_block; diff --git a/hawk/lib/hawk.h b/hawk/lib/hawk.h index f2b0dbb7..952a7512 100644 --- a/hawk/lib/hawk.h +++ b/hawk/lib/hawk.h @@ -129,29 +129,29 @@ struct hawk_rtx_alt_t /* ------------------------------------------------------------------------ */ -typedef struct hawk_gci_t hawk_gci_t; -struct hawk_gci_t +typedef struct hawk_gch_t hawk_gch_t; +struct hawk_gch_t { - hawk_gci_t* gc_prev; - hawk_gci_t* gc_next; + hawk_gch_t* gc_prev; + hawk_gch_t* gc_next; hawk_uintptr_t gc_refs; }; #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 -# define hawk_val_to_gci(v) (((hawk_gci_t*)(v)) - 1) -# define hawk_gci_to_val(gci) ((hawk_val_t*)(((hawk_gci_t*)(gci)) + 1)) +# define hawk_val_to_gch(v) (((hawk_gch_t*)(v)) - 1) +# define hawk_gch_to_val(gch) ((hawk_val_t*)(((hawk_gch_t*)(gch)) + 1)) #endif /** diff --git a/hawk/lib/run.c b/hawk/lib/run.c index f3a8ea0b..85fdc758 100644 --- a/hawk/lib/run.c +++ b/hawk/lib/run.c @@ -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_LCLIDX: case HAWK_NDE_ARGIDX: + #if !defined(HAWK_ENABLE_GC) if (HAWK_RTX_GETVALTYPE(rtx, val) == HAWK_VAL_MAP) { /* a map cannot become a member of a map */ errnum = HAWK_EMAPTOIDX; goto exit_on_error; } + #endif ret = do_assignment_idx(rtx, (hawk_nde_var_t*)var, val); 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); return HAWK_NULL; } - #if !defined(HAWK_ENABLE_GC) else if (vtype == HAWK_VAL_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); return HAWK_NULL; } - #endif } 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); return HAWK_NULL; } - #if !defined(HAWK_ENABLE_GC) else if (vtype == HAWK_VAL_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); return HAWK_NULL; } - #endif } 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); return HAWK_NULL; } - #if !defined(HAWK_ENABLE_GC) else if (vtype == HAWK_VAL_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); return HAWK_NULL; } - #endif } 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_LCLIDX || var->type == HAWK_NDE_ARGIDX) && var->idx != HAWK_NULL); +#if !defined(HAWK_ENABLE_GC) HAWK_ASSERT (HAWK_RTX_GETVALTYPE (rtx, val) != HAWK_VAL_MAP); +#endif retry: switch (var->type) diff --git a/hawk/lib/val.c b/hawk/lib/val.c index 86a080d2..f278a052 100644 --- a/hawk/lib/val.c +++ b/hawk/lib/val.c @@ -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) { - hawk_gci_t* gci; + hawk_gch_t* gch; - gci = (hawk_gci_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*gci) + size); - if (HAWK_UNLIKELY(!gci)) return HAWK_NULL; + gch = (hawk_gch_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*gch) + size); + 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; - gci->gc_prev = list->gc_prev; - gci->gc_prev->gc_next = gci; - list->gc_prev = gci; + gch->gc_next = list; + gch->gc_prev = list->gc_prev; + gch->gc_prev->gc_next = gch; + 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; - gci->gc_next->gc_prev = gci->gc_prev; + if (list->gc_next != list) + { + 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) { - 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; - - 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_gch_t* gch; hawk_val_t* v, * iv; hawk_map_itr_t itr; hawk_map_pair_t* pair; - gci = list->gc_next; - while (gci != list) + /* phase 1 - copy the reference count field from the value header to the gc header */ + 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 */ 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); if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) { -printf ("decrementing...\n"); - hawk_val_to_gci(iv)->gc_refs--; + hawk_val_to_gch(iv)->gc_refs--; } 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; - while (gci != list) + gch = list->gc_next; + while (gch != list) { - printf (" %p %d\n", gci, (int)gci->gc_refs); - gci = gci->gc_next; + printf (" %p %d\n", gch, (int)gch->gc_refs); + gch = gch->gc_next; } 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; - - 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_gch_t* gch, * tmp; hawk_val_t* v, * iv; hawk_map_itr_t itr; hawk_map_pair_t* pair; - gci = reachable_list->gc_next; - while (gci != reachable_list) + gch = list->gc_next; + 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 */ /* 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); if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc) { - igci = hawk_val_to_gci(iv); - if (igci->gc_refs != GCI_MOVED) + tmp = hawk_val_to_gch(iv); + if (tmp->gc_refs != GCH_MOVED) { - gc_unchain_gci (igci); - gc_chain_gci (reachable_list, igci); - igci->gc_refs = GCI_MOVED; + gc_unchain_gch (tmp); + gc_chain_gch (reachable_list, tmp); + tmp->gc_refs = GCH_MOVED; } } 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) { - 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_dump_refs (rtx, &rtx->gc.all); - - - /*reachable.gc_prev = &reachable; + reachable.gc_prev = &reachable; reachable.gc_next = &reachable; - gc_move_roots (&rtx->gc.all, &reachable);*/ -/* - gc_move_reachables_from_root (&reachable, &reachable); + gc_move_reachables (&rtx->gc.all, &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 - move_reachable_back_to rtx->gc.all???*/ + gc_move_gchs (&rtx->gc.all, &reachable); + +printf ("collecting garbage.done ..\n"); } +#endif + /* --------------------------------------------------------------------- */ 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); #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); } @@ -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 hawk_rtx_freemem (rtx, ((hawk_val_rex_t*)val)->ptr); */ - + /* code is just a pointer to a regular expression stored * 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]); @@ -1074,7 +1115,7 @@ void hawk_rtx_freeval (hawk_rtx_t* rtx, hawk_val_t* val, int cache) rtx->gc.all_count--; gc_unchain_val (val); 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 hawk_map_fini (((hawk_val_map_t*)val)->map); hawk_rtx_freemem (rtx, val);