changed mark-sweep gc to use the stack explicitly
This commit is contained in:
		
							
								
								
									
										87
									
								
								moo/lib/gc.c
									
									
									
									
									
								
							
							
						
						
									
										87
									
								
								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, 
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user