From e0d4e6abfddc1dd9d5ac1af6ca90b330bd7348e0 Mon Sep 17 00:00:00 2001 From: "hyunghwan.chung" Date: Mon, 26 Oct 2020 16:43:09 +0000 Subject: [PATCH] changed mark-sweep gc to use the stack explicitly --- moo/lib/gc.c | 87 +++++++++++++++++++++++++++++++++++++++++---------- moo/lib/moo.c | 44 +++++++++++++++++++------- moo/lib/moo.h | 16 +++++++++- moo/lib/obj.c | 16 +++++++--- moo/lib/std.c | 4 +-- 5 files changed, 131 insertions(+), 36 deletions(-) diff --git a/moo/lib/gc.c b/moo/lib/gc.c index 50527de..9b60c58 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -646,11 +646,11 @@ int moo_ignite (moo_t* moo, moo_oow_t heapsz) if (moo->heap) moo_killheap (moo, moo->heap); moo->heap = moo_makeheap(moo, heapsz); - if (!moo->heap) return -1; + if (MOO_UNLIKELY(!moo->heap)) return -1; moo->igniting = 1; moo->_nil = moo_allocbytes(moo, MOO_SIZEOF(moo_obj_t)); - if (!moo->_nil) goto oops; + if (MOO_UNLIKELY(!moo->_nil)) goto oops; moo->_nil->_flags = MOO_OBJ_MAKE_FLAGS(MOO_OBJ_TYPE_OOP, MOO_SIZEOF(moo_oop_t), 0, 1, moo->igniting, 0, 0, 0, 0, 0); moo->_nil->_size = 0; @@ -799,6 +799,9 @@ static moo_rbt_walk_t call_module_gc (moo_rbt_t* rbt, moo_rbt_pair_t* pair, void #if defined(MOO_ENABLE_GC_MARK_SWEEP) + + +#if 0 static MOO_INLINE void gc_mark (moo_t* moo, moo_oop_t oop) { moo_oow_t i, sz; @@ -840,6 +843,63 @@ static MOO_INLINE void gc_mark (moo_t* moo, moo_oop_t oop) } } } +#else +static MOO_INLINE void gc_mark_object (moo_t* moo, moo_oop_t oop) +{ +#if defined(MOO_SUPPORT_GC_DURING_IGNITION) + if (!oop) return; +#endif + if (!MOO_OOP_IS_POINTER(oop) || MOO_OBJ_GET_FLAGS_MOVED(oop)) return; /* non-pointer or already marked */ + + MOO_OBJ_SET_FLAGS_MOVED(oop, 1); /* mark */ +MOO_ASSERT (moo, moo->gci.stack.len < moo->gci.stack.capa); + moo->gci.stack.ptr[moo->gci.stack.len++] = oop; /* push */ +if (moo->gci.stack.len > moo->gci.stack.max) moo->gci.stack.max = moo->gci.stack.len; +} + +static MOO_INLINE void gc_scan_stack (moo_t* moo) +{ + moo_oop_t oop; + + while (moo->gci.stack.len > 0) + { + oop = moo->gci.stack.ptr[--moo->gci.stack.len]; + + gc_mark_object (moo, (moo_oop_t)MOO_OBJ_GET_CLASS(oop)); + + if (MOO_OBJ_GET_FLAGS_TYPE(oop) == MOO_OBJ_TYPE_OOP) + { + moo_oow_t size, i; + + /* is it really better to use a flag bit in the header to + * determine that it is an instance of process? */ + if (MOO_UNLIKELY(MOO_OBJ_GET_FLAGS_PROC(oop))) + { + /* the stack in a process object doesn't need to be + * scanned in full. the slots above the stack pointer + * are garbages. */ + size = MOO_PROCESS_NAMED_INSTVARS + MOO_OOP_TO_SMOOI(((moo_oop_process_t)oop)->sp) + 1; + MOO_ASSERT (moo, size <= MOO_OBJ_GET_SIZE(oop)); + } + else + { + size = MOO_OBJ_GET_SIZE(oop); + } + + for (i = 0; i < size; i++) + { + gc_mark_object (moo, MOO_OBJ_GET_OOP_VAL(oop, i)); + } + } + } +} + +static MOO_INLINE void gc_mark (moo_t* moo, moo_oop_t oop) +{ + gc_mark_object (moo, oop); + gc_scan_stack (moo); +} +#endif static MOO_INLINE void gc_mark_root (moo_t* moo) { @@ -856,10 +916,6 @@ static MOO_INLINE void gc_mark_root (moo_t* moo) moo->processor->active->sp = MOO_SMOOI_TO_OOP(moo->sp); } - #if 0 - if (moo->active_context) moo->active_context->ip = MOO_SMOOI_TO_OOP(moo->ip); /* no need to commit the instruction pointer */ - #endif - gc_mark (moo, moo->_nil); gc_mark (moo, moo->_true); gc_mark (moo, moo->_false); @@ -946,7 +1002,7 @@ static MOO_INLINE void gc_sweep (moo_t* moo) moo_oop_t obj; prev = MOO_NULL; - curr = moo->gch; + curr = moo->gci.b; while (curr) { next = curr->next; @@ -962,9 +1018,9 @@ static MOO_INLINE void gc_sweep (moo_t* moo) { /* destroy */ if (prev) prev->next = next; - else moo->gch = next; -//if (!moo->igniting) -//MOO_DEBUG2(moo, "** DESTROYING curr %p %O\n", curr, obj); + else moo->gci.b = next; + + moo->gci.bsz -= MOO_SIZEOF(moo_obj_t) + moo_getobjpayloadbytes(moo, obj); moo_freemem (moo, curr); } @@ -1126,10 +1182,12 @@ static moo_uint8_t* scan_heap_space (moo_t* moo, moo_uint8_t* ptr, moo_uint8_t** void moo_gc (moo_t* moo) { #if defined(MOO_ENABLE_GC_MARK_SWEEP) - MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Starting GC (mark-sweep)\n"); + MOO_LOG1 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Starting GC (mark-sweep) - gci.bsz = %zu\n", moo->gci.bsz); +moo->gci.stack.len = 0; +/*moo->gci.stack.max = 0;*/ gc_mark_root (moo); gc_sweep (moo); - MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Finished GC (mark-sweep)\n"); + MOO_LOG2 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Finished GC (mark-sweep) - gci.bsz = %zu, gci.stack.max %zu\n", moo->gci.bsz, moo->gci.stack.max); #else /* * move a referenced object to the new heap. @@ -1152,11 +1210,6 @@ void moo_gc (moo_t* moo) /* commit the stack pointer to the active process * to limit scanning of the process stack properly */ moo->processor->active->sp = MOO_SMOOI_TO_OOP(moo->sp); - - #if 0 /* ip doesn't need to be committed */ - /* store the instruction pointer to the active context */ - moo->active_context->ip = MOO_SMOOI_TO_OOP(moo->ip); - #endif } MOO_LOG4 (moo, MOO_LOG_GC | MOO_LOG_INFO, diff --git a/moo/lib/moo.c b/moo/lib/moo.c index eb8f5bd..60783fa 100644 --- a/moo/lib/moo.c +++ b/moo/lib/moo.c @@ -132,9 +132,13 @@ int moo_init (moo_t* moo, moo_mmgr_t* mmgr, moo_cmgr_t* cmgr, const moo_vmprim_t * reallocation fails */ /* +1 required for consistency with put_oocs and put_ooch in fmtout.c */ moo->log.ptr = moo_allocmem(moo, (moo->log.capa + 1) * MOO_SIZEOF(*moo->log.ptr)); - if (!moo->log.ptr) goto oops; + if (MOO_UNLIKELY(!moo->log.ptr)) goto oops; - if (moo_rbt_init (&moo->modtab, moo, MOO_SIZEOF(moo_ooch_t), 1) <= -1) goto oops; + moo->gci.stack.capa = MOO_ALIGN_POW2(1, 1024); /* TODO: is this a good initial size? */ + moo->gci.stack.ptr = moo_allocmem(moo, (moo->gci.stack.capa + 1) * MOO_SIZEOF(*moo->gci.stack.ptr)); + if (MOO_UNLIKELY(!moo->gci.stack.ptr)) goto oops; + + if (moo_rbt_init(&moo->modtab, moo, MOO_SIZEOF(moo_ooch_t), 1) <= -1) goto oops; modtab_inited = 1; moo_rbt_setstyle (&moo->modtab, moo_get_rbt_style(MOO_RBT_STYLE_INLINE_COPIERS)); @@ -153,8 +157,16 @@ int moo_init (moo_t* moo, moo_mmgr_t* mmgr, moo_cmgr_t* cmgr, const moo_vmprim_t oops: if (modtab_inited) moo_rbt_fini (&moo->modtab); - if (moo->log.ptr) moo_freemem (moo, moo->log.ptr); - moo->log.capa = 0; + if (moo->gci.stack.ptr) + { + moo_freemem (moo, moo->gci.stack.ptr); + moo->gci.stack.capa = 0; + } + if (moo->log.ptr) + { + moo_freemem (moo, moo->log.ptr); + moo->log.capa = 0; + } return -1; } @@ -251,23 +263,33 @@ void moo_fini (moo_t* moo) if (moo->heap) moo_killheap (moo, moo->heap); #if defined(MOO_ENABLE_GC_MARK_SWEEP) - if (moo->gch) + if (moo->gci.b) { moo_gchdr_t* next; - do { - next = moo->gch->next; - moo_freemem (moo, moo->gch); - moo->gch = next; + next = moo->gci.b->next; + + moo->gci.bsz -= MOO_SIZEOF(moo_obj_t) + moo_getobjpayloadbytes(moo, (moo_oop_t)(moo->gci.b + 1)); + moo_freemem (moo, moo->gci.b); + moo->gci.b = next; } - while (moo->gch); + while (moo->gci.b); + + MOO_ASSERT (moo, moo->gci.bsz == 0); + } + + if (moo->gci.stack.ptr) + { + moo_freemem (moo, moo->gci.stack.ptr); + moo->gci.stack.ptr = 0; + moo->gci.stack.capa = 0; + moo->gci.stack.len = 0; } #endif moo_finidbgi (moo); - for (i = 0; i < MOO_COUNTOF(moo->sbuf); i++) { if (moo->sbuf[i].ptr) diff --git a/moo/lib/moo.h b/moo/lib/moo.h index f73d0a4..3939223 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -1797,7 +1797,21 @@ struct moo_t } stat; #if defined(MOO_ENABLE_GC_MARK_SWEEP) - moo_gchdr_t* gch; + struct + { + moo_gchdr_t* b; /* object blocks allocated */ + moo_oow_t bsz; /* total size of object blocks allocated */ + moo_oow_t threshold; + + struct + { + moo_oop_t* ptr; + moo_oow_t capa; + moo_oow_t len; + + moo_oow_t max; + } stack; + } gci; #endif #if defined(MOO_INCLUDE_COMPILER) diff --git a/moo/lib/obj.c b/moo/lib/obj.c index 281ea96..5cb58af 100644 --- a/moo/lib/obj.c +++ b/moo/lib/obj.c @@ -46,7 +46,12 @@ void* moo_allocbytes (moo_t* moo, moo_oow_t size) } else { -// TODO: perform GC if allocation got above threshold... + if (moo->gci.bsz >= moo->gci.threshold) + { + moo_gc (moo); + moo->gci.threshold = moo->gci.bsz + 100000; /* TODO: change this fomula */ + } + gch = (moo_gchdr_t*)moo_callocmem(moo, MOO_SIZEOF(*gch) + size); if (!gch && moo->errnum == MOO_EOOMEM && !(moo->option.trait & MOO_TRAIT_NOGC)) { @@ -57,8 +62,9 @@ void* moo_allocbytes (moo_t* moo, moo_oow_t size) } } - gch->next = moo->gch; - moo->gch = gch; + gch->next = moo->gci.b; + moo->gci.b = gch; + moo->gci.bsz += size; ptr = (moo_uint8_t*)(gch + 1); #else @@ -130,7 +136,7 @@ moo_oop_t moo_allocoopobjwithtrailer (moo_t* moo, moo_oow_t size, const moo_oob_ nbytes_aligned = MOO_ALIGN(nbytes, MOO_SIZEOF(moo_oop_t)); hdr = (moo_oop_oop_t)moo_allocbytes(moo, MOO_SIZEOF(moo_obj_t) + nbytes_aligned); - if (!hdr) return MOO_NULL; + if (MOO_UNLIKELY(!hdr)) return MOO_NULL; hdr->_flags = MOO_OBJ_MAKE_FLAGS(MOO_OBJ_TYPE_OOP, MOO_SIZEOF(moo_oop_t), 0, 0, moo->igniting, 0, 0, 1, 0, 1); /* TRAILER -> 1, UNCOPYABLE -> 1 */ MOO_OBJ_SET_SIZE (hdr, size); @@ -177,7 +183,7 @@ static MOO_INLINE moo_oop_t alloc_numeric_array (moo_t* moo, const void* ptr, mo * of the allocated space to be an even number. * see MOO_OOP_IS_NUMERIC() and MOO_OOP_IS_POINTER() */ hdr = (moo_oop_t)moo_allocbytes(moo, MOO_SIZEOF(moo_obj_t) + nbytes_aligned); - if (!hdr) return MOO_NULL; + if (MOO_UNLIKELY(!hdr)) return MOO_NULL; hdr->_flags = MOO_OBJ_MAKE_FLAGS(type, unit, extra, 0, moo->igniting, 0, 0, 0, 0, 0); /* TODO: review. ngc and perm flags seems to conflict with each other ... the diff is that ngc is malloc() and perm is allocated in the perm heap */ hdr->_size = len; diff --git a/moo/lib/std.c b/moo/lib/std.c index 3a5235c..8d1f399 100644 --- a/moo/lib/std.c +++ b/moo/lib/std.c @@ -1350,8 +1350,8 @@ static void backtrace_stack_frames (moo_t* moo) moo_oow_t btsize; char** btsyms; - btsize = backtrace (btarray, MOO_COUNTOF(btarray)); - btsyms = backtrace_symbols (btarray, btsize); + btsize = backtrace(btarray, MOO_COUNTOF(btarray)); + btsyms = backtrace_symbols(btarray, btsize); if (btsyms) { moo_oow_t i;