implementing an alternative mark-sweep GC

This commit is contained in:
hyunghwan.chung 2020-10-18 16:53:43 +00:00
parent c29b256fec
commit 29c919626f
3 changed files with 193 additions and 67 deletions

View File

@ -5412,53 +5412,6 @@ static MOO_INLINE void do_return_from_block (moo_t* moo)
static MOO_INLINE int make_block (moo_t* moo) static MOO_INLINE int make_block (moo_t* moo)
{ {
#if 0
moo_oop_context_t blkctx;
moo_oob_t b1, b2;
/* b1 - number of block arguments
* b2 - number of block temporaries */
FETCH_PARAM_CODE_TO (moo, b1);
FETCH_PARAM_CODE_TO (moo, b2);
LOG_INST2 (moo, "make_block %zu %zu", b1, b2);
MOO_ASSERT (moo, b1 >= 0);
MOO_ASSERT (moo, b2 >= b1);
/* the block context object created here is used as a base
* object for block context activation. pf_block_value()
* clones a block context and activates the cloned context.
* this base block context is created with no stack for
* this reason */
blkctx = (moo_oop_context_t)moo_instantiate(moo, moo->_block_context, MOO_NULL, 0);
if (!blkctx) return -1;
/* the long forward jump instruction has the format of
* 11000100 KKKKKKKK or 11000100 KKKKKKKK KKKKKKKK
* depending on MOO_BCODE_LONG_PARAM_SIZE. change 'ip' to point to
* the instruction after the jump. */
blkctx->ip = MOO_SMOOI_TO_OOP(moo->ip + MOO_BCODE_LONG_PARAM_SIZE + 1);
/* stack pointer below the bottom. this base block context
* has an empty stack anyway. */
blkctx->sp = MOO_SMOOI_TO_OOP(-1);
/* the number of arguments for a block context is local to the block */
blkctx->method_or_nargs = MOO_SMOOI_TO_OOP(b1);
/* the number of temporaries here is an accumulated count including
* the number of temporaries of a home context */
blkctx->ntmprs = MOO_SMOOI_TO_OOP(b2);
/* set the home context where it's defined */
MOO_STORE_OOP (moo, &blkctx->home, (moo_oop_t)moo->active_context);
/* no source for a base block context. */
blkctx->receiver_or_base = moo->_nil;
MOO_STORE_OOP (moo, (moo_oop_t*)&blkctx->origin, (moo_oop_t)moo->active_context->origin);
/* push the new block context to the stack of the active context */
MOO_STACK_PUSH (moo, (moo_oop_t)blkctx);
return 0;
#else
moo_oop_block_t block; moo_oop_block_t block;
moo_oob_t b1, b2; moo_oob_t b1, b2;
@ -5497,7 +5450,6 @@ static MOO_INLINE int make_block (moo_t* moo)
/* push the new block context to the stack of the active context */ /* push the new block context to the stack of the active context */
MOO_STACK_PUSH (moo, (moo_oop_t)block); MOO_STACK_PUSH (moo, (moo_oop_t)block);
return 0; return 0;
#endif
} }
static int __execute (moo_t* moo) static int __execute (moo_t* moo)

View File

@ -705,6 +705,7 @@ static void compact_symbol_table (moo_t* moo, moo_oop_t _nil)
MOO_ASSERT (moo, tmp != _nil); MOO_ASSERT (moo, tmp != _nil);
MOO_LOG2 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Compacting away a symbol - %.*js\n", MOO_OBJ_GET_SIZE(tmp), MOO_OBJ_GET_CHAR_SLOT(tmp)); MOO_LOG2 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Compacting away a symbol - %.*js\n", MOO_OBJ_GET_SIZE(tmp), MOO_OBJ_GET_CHAR_SLOT(tmp));
/* delete a symbol table entry which has not been moved (excluding permanent entries) */
for (i = 0, x = index, y = index; i < bucket_size; i++) for (i = 0, x = index, y = index; i < bucket_size; i++)
{ {
y = (y + 1) % bucket_size; y = (y + 1) % bucket_size;
@ -781,12 +782,197 @@ moo_oow_t moo_getobjpayloadbytes (moo_t* moo, moo_oop_t oop)
return nbytes; return nbytes;
} }
static moo_rbt_walk_t call_module_gc (moo_rbt_t* rbt, moo_rbt_pair_t* pair, void* ctx)
{
moo_t* moo = (moo_t*)ctx;
moo_mod_data_t* mdp;
mdp = MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, mdp != MOO_NULL);
if (mdp->mod.gc) mdp->mod.gc (moo, &mdp->mod);
return MOO_RBT_WALK_FORWARD;
}
/* ----------------------------------------------------------------------- */
#if defined(MOO_ENABLE_GC_MARK_SWEEP)
static MOO_INLINE void gc_mark (moo_t* moo, moo_oop_t oop)
{
moo_oow_t i, sz;
#if defined(MOO_SUPPORT_GC_DURING_IGNITION)
if (!oop) return;
#endif
if (!MOO_OOP_IS_POINTER(oop)) return;
if (MOO_OBJ_GET_FLAGS_MOVED(oop)) return; /* already marked */
MOO_OBJ_SET_FLAGS_MOVED(oop, 1); /* mark */
gc_mark (moo, (moo_oop_t)MOO_OBJ_GET_CLASS(oop)); /* TODO: remove recursion */
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++)
{
moo_oop_t tmp = MOO_OBJ_GET_OOP_VAL(oop, i);
if (MOO_OOP_IS_POINTER(tmp)) gc_mark (moo, tmp); /* TODO: no resursion */
}
}
}
static MOO_INLINE void gc_mark_root (moo_t* moo)
{
moo_oow_t i, gcfin_count;
moo_evtcb_t* cb;
gc_mark (moo, moo->_nil);
gc_mark (moo, moo->_true);
gc_mark (moo, moo->_false);
for (i = 0; i < MOO_COUNTOF(kernel_classes); i++)
{
moo_oop_t tmp;
tmp = *(moo_oop_t*)((moo_uint8_t*)moo + kernel_classes[i].offset);
gc_mark (moo, tmp);
}
gc_mark (moo, (moo_oop_t)moo->sysdic);
gc_mark (moo, (moo_oop_t)moo->processor);
gc_mark (moo, (moo_oop_t)moo->nil_process);
gc_mark (moo, (moo_oop_t)moo->dicnewsym);
gc_mark (moo, (moo_oop_t)moo->dicputassocsym);
gc_mark (moo, (moo_oop_t)moo->does_not_understand_sym);
gc_mark (moo, (moo_oop_t)moo->primitive_failed_sym);
gc_mark (moo, (moo_oop_t)moo->unwindto_return_sym);
for (i = 0; i < moo->sem_list_count; i++)
{
gc_mark (moo, (moo_oop_t)moo->sem_list[i]);
}
for (i = 0; i < moo->sem_heap_count; i++)
{
gc_mark (moo, (moo_oop_t)moo->sem_heap[i]);
}
for (i = 0; i < moo->sem_io_tuple_count; i++)
{
if (moo->sem_io_tuple[i].sem[MOO_SEMAPHORE_IO_TYPE_INPUT])
gc_mark (moo, (moo_oop_t)moo->sem_io_tuple[i].sem[MOO_SEMAPHORE_IO_TYPE_INPUT]);
if (moo->sem_io_tuple[i].sem[MOO_SEMAPHORE_IO_TYPE_OUTPUT])
gc_mark (moo, (moo_oop_t)moo->sem_io_tuple[i].sem[MOO_SEMAPHORE_IO_TYPE_OUTPUT]);
}
gc_mark (moo, (moo_oop_t)moo->sem_gcfin);
for (i = 0; i < moo->proc_map_capa; i++)
{
gc_mark (moo, moo->proc_map[i]);
}
for (i = 0; i < moo->volat_count; i++)
{
gc_mark (moo, *moo->volat_stack[i]);
}
if (moo->initial_context) gc_mark (moo, (moo_oop_t)moo->initial_context);
if (moo->active_context) gc_mark (moo, (moo_oop_t)moo->active_context);
if (moo->active_method) gc_mark (moo, (moo_oop_t)moo->active_method);
moo_rbt_walk (&moo->modtab, call_module_gc, moo);
for (cb = moo->evtcb_list; cb; cb = cb->next)
{
if (cb->gc) cb->gc (moo);
}
gcfin_count = move_finalizable_objects (moo); /* mark finalizable objects */
if (moo->symtab)
{
compact_symbol_table (moo, moo->_nil); /* delete symbol table entries that are not marked */
#if 0
gc_mark (moo, (moo_oop_t)moo->symtab); /* mark the symbol table */
#else
MOO_OBJ_SET_FLAGS_MOVED(moo->symtab, 1); /* mark */
MOO_OBJ_SET_FLAGS_MOVED(moo->symtab->bucket, 1); /* mark */
#endif
}
if (gcfin_count > 0) moo->sem_gcfin_sigreq = 1;
if (moo->active_method) moo->active_code = MOO_METHOD_GET_CODE_BYTE(moo->active_method); /* update moo->active_code */
/* invalidate method cache. TODO: GCing entries on the method cache is also one way instead of full invalidation */
moo_clearmethodcache (moo);
}
static MOO_INLINE void gc_sweep (moo_t* moo)
{
moo_gchdr_t* curr, * next, * prev;
moo_oop_t obj;
prev = MOO_NULL;
curr = moo->gch;
while (curr)
{
next = curr->next;
obj = (moo_oop_t)(curr + 1);
if (MOO_OBJ_GET_FLAGS_MOVED(obj))
{
/* unmark */
MOO_OBJ_SET_FLAGS_MOVED (obj, 0);
prev = curr;
}
else
{
/* destroy */
if (prev) prev->next = next;
else moo->gch = next;
moo_freemem (moo, curr);
}
curr = next;
}
}
#endif
/* ----------------------------------------------------------------------- */
moo_oop_t moo_moveoop (moo_t* moo, moo_oop_t oop) moo_oop_t moo_moveoop (moo_t* moo, moo_oop_t oop)
{ {
#if defined(MOO_SUPPORT_GC_DURING_IGNITION) #if defined(MOO_SUPPORT_GC_DURING_IGNITION)
if (!oop) return oop; if (!oop) return oop;
#endif #endif
#if defined(MOO_ENABLE_GC_MARK_SWEEP)
/* TODO: temporary... */
gc_mark (moo, oop);
return oop;
#endif
if (!MOO_OOP_IS_POINTER(oop)) return oop; if (!MOO_OOP_IS_POINTER(oop)) return oop;
if (MOO_OBJ_GET_FLAGS_PERM(oop)) return oop; if (MOO_OBJ_GET_FLAGS_PERM(oop)) return oop;
@ -922,25 +1108,14 @@ static moo_uint8_t* scan_heap_space (moo_t* moo, moo_uint8_t* ptr, moo_uint8_t**
return ptr; return ptr;
} }
static moo_rbt_walk_t call_module_gc (moo_rbt_t* rbt, moo_rbt_pair_t* pair, void* ctx)
{
moo_t* moo = (moo_t*)ctx;
moo_mod_data_t* mdp;
mdp = MOO_RBT_VPTR(pair);
MOO_ASSERT (moo, mdp != MOO_NULL);
if (mdp->mod.gc) mdp->mod.gc (moo, &mdp->mod);
return MOO_RBT_WALK_FORWARD;
}
void moo_gc (moo_t* moo) void moo_gc (moo_t* moo)
{ {
#if defined(MOO_ENABLE_GC_MARK_SWEEP) #if defined(MOO_ENABLE_GC_MARK_SWEEP)
/* TODO: */ MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Starting GC (mark-sweep)\n");
gc_mark_root (moo);
gc_sweep (moo);
MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_INFO, "Finished GC (mark-sweep)\n");
#else #else
/* /*
* move a referenced object to the new heap. * move a referenced object to the new heap.
@ -958,7 +1133,6 @@ void moo_gc (moo_t* moo)
if (moo->active_context) if (moo->active_context)
{ {
/* TODO: verify if this is correct */ /* TODO: verify if this is correct */
MOO_ASSERT (moo, (moo_oop_t)moo->processor != moo->_nil); MOO_ASSERT (moo, (moo_oop_t)moo->processor != moo->_nil);
MOO_ASSERT (moo, (moo_oop_t)moo->processor->active != moo->_nil); MOO_ASSERT (moo, (moo_oop_t)moo->processor->active != moo->_nil);
/* store the stack pointer to the active process */ /* store the stack pointer to the active process */

View File

@ -40,18 +40,18 @@ void* moo_allocbytes (moo_t* moo, moo_oow_t size)
#if defined(MOO_ENABLE_GC_MARK_SWEEP) #if defined(MOO_ENABLE_GC_MARK_SWEEP)
if (MOO_UNLIKELY(moo->igniting)) if (MOO_UNLIKELY(moo->igniting))
{ {
gch = (moo_gchdr_t*)moo_allocmem(moo, MOO_SIZEOF(*gch) + size); gch = (moo_gchdr_t*)moo_callocmem(moo, MOO_SIZEOF(*gch) + size);
if (MOO_UNLIKELY(!gch)) return MOO_NULL; if (MOO_UNLIKELY(!gch)) return MOO_NULL;
} }
else else
{ {
// TODO: perform GC if allocation got above threshold... // TODO: perform GC if allocation got above threshold...
gch = (moo_gchdr_t*)moo_allocmem(moo, MOO_SIZEOF(*gch) + size); gch = (moo_gchdr_t*)moo_callocmem(moo, MOO_SIZEOF(*gch) + size);
if (!gch && moo->errnum == MOO_EOOMEM && !(moo->option.trait & MOO_TRAIT_NOGC)) if (!gch && moo->errnum == MOO_EOOMEM && !(moo->option.trait & MOO_TRAIT_NOGC))
{ {
moo_gc (moo); moo_gc (moo);
MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_INFO, "GC completed\n"); /* TODO: add more inforamtion */ MOO_LOG0 (moo, MOO_LOG_GC | MOO_LOG_INFO, "GC completed\n"); /* TODO: add more inforamtion */
gch = (moo_gchdr_t*)moo_allocmem(moo, MOO_SIZEOF(*gch) + size); gch = (moo_gchdr_t*)moo_callocmem(moo, MOO_SIZEOF(*gch) + size);
if (MOO_UNLIKELY(!gch)) return MOO_NULL; if (MOO_UNLIKELY(!gch)) return MOO_NULL;
} }
} }