added some experimental code to support object finalization

This commit is contained in:
hyunghwan.chung 2017-07-20 16:33:53 +00:00
parent fc121cd70a
commit 03fd02d59b
10 changed files with 481 additions and 75 deletions

View File

@ -130,6 +130,12 @@ extend Apex
else { self primitiveFailed }
}
(* ------------------------------------------------------------------
* FINALIZATION SUPPORT
* ------------------------------------------------------------------ *)
method(#dual,#primitive) addToBeFinalized.
##method(#dual,#primitive) removeToBeFinalized.
(* ------------------------------------------------------------------
* HASHING
* ------------------------------------------------------------------ *)

View File

@ -10,6 +10,45 @@
class System(Apex)
{
method(#class) startup(class_name, method_name)
{
| class ret |
class := System at: class_name.
if (class isError)
{
System error: ('Cannot find the class - ' & class_name).
}.
## start the gc finalizer process
[ self __gc_finalizer ] fork.
## TODO: change the method signature to variadic and pass extra arguments to perform???
ret := class perform: method_name.
#### System logNl: '======= END of startup ==============='.
^ret.
}
method(#class) __gc_finalizer
{
| tmp |
while (true)
{
## TODO: exit from this loop when there are no other processes running.
while ((tmp := self _popCollectable) notError)
{
## TODO: Do i have to protected this in an exception handler???
tmp finalize.
}.
System logNl: 'gc_waiting....'.
Processor sleepFor: 1. ## TODO: wait on semaphore instead..
}
}
method(#class,#primitive) _popCollectable.
}
pooldic System.Log

View File

@ -300,10 +300,13 @@ class X11.Widget(Object)
method onPaintEvent: paint_event
{
System logNl: 'Widget...... onPaintEvent YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.'.
}
method onButtonEvent: event
method onMouseButtonEvent: event
{
}
method onKeyEvent: event
{
}
@ -337,23 +340,45 @@ class X11.Label(X11.Widget)
method onPaintEvent: paint_event
{
| gc |
System logNl: 'LABEL GC...... onPaintEvent YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY.'.
gc := selfns.GC new: self.
[
gc foreground: self.fgcolor;
gc foreground: self.bgcolor;
fontName: '-misc-fixed-medium-r-normal-ko-18-120-100-100-c-180-iso10646-1';
apply.
gc fillRectangle (0, 0, self.width, self.height).
gc foreground: self.fgcolor; apply.
gc drawRectangle (0, 0, self.width - 1, self.height - 1).
##gc fillRectangle (0, 0, self.width, self.height).
##gc drawLine (0, y, CTRLWIDE, y).
##gc drawLine (0, y + CHIGH + 4, CTRLWIDE, Y+CHIGH+4).
gc drawString(10, 10, self.text).
] ensure: [ gc dispose ]
}
}
class X11.Button(X11.Label)
{
method onMouseButtonEvent: llevent
{
| type x |
type := llevent type.
if (type == X11.LLEventType.BUTTON_PRESS)
{
x := self.fgcolor.
self.fgcolor := self.bgcolor.
self.bgcolor := x.
self onPaintEvent: llevent.
}
elsif (type == X11.LLEventType.BUTTON_RELEASE)
{
x := self.fgcolor.
self.fgcolor := self.bgcolor.
self.bgcolor := x.
self onPaintEvent: llevent.
}
}
}
class X11.Composite(X11.Widget)
{
var children.
@ -646,8 +671,9 @@ extend X11
widget onPaintEvent: llevent
}
method __handle_button_event: event on: widget
method __handle_button_event: llevent on: widget
{
widget onMouseButtonEvent: llevent
}
method __handle_destroy_notify: event on: widget
@ -664,8 +690,9 @@ extend X11
widget close: event.
}
method __handle_key_event: event on: widget
method __handle_key_event: llevent on: widget
{
widget onKeyEvent: llevent
}
method __handle_shell_close: llevent on: widget
@ -675,7 +702,18 @@ extend X11
}
class Fx(Object)
{
method initialize
{
self addToBeFinalized.
}
method finalize
{
System logNl: 'Greate... FX instance finalized'.
}
}
class MyObject(Object)
{
@ -706,16 +744,23 @@ class MyObject(Object)
comp1 add: (X11.Label new text: '간다'; width: 100; height: 100).
comp1 add: (X11.Label new text: 'crayon'; x: 90; y: 90; width: 100; height: 100).
## self.shell1 add: (X11.Label new text: 'xxxxxxxx'; width: 100; height: 100).
self.shell1 add: (X11.Label new text: 'crayon'; x: 90; y: 90; width: 100; height: 100).
self.shell1 add: (X11.Button new text: '크레용crayon'; x: 90; y: 90; width: 100; height: 100).
self.shell2 add: (X11.Label new text: 'crayon'; x: 90; y: 90; width: 100; height: 100).
self.shell3 add: (X11.Label new text: 'crayon'; x: 90; y: 90; width: 100; height: 100).
self.shell2 add: (X11.Button new text: 'crayon'; x: 90; y: 90; width: 100; height: 100).
self.shell3 add: (X11.Button new text: 'crayon'; x: 90; y: 90; width: 100; height: 100).
self.shell1 realize.
self.shell2 realize.
self.shell3 realize.
self.disp1 enterEventLoop. ## this is not a blocking call. it spawns another process.
self.disp2 enterEventLoop.
comp1 := Fx new.
Fx new.
Fx new.
Fx new.
}
method(#class) main

View File

@ -4354,7 +4354,7 @@ static int compile_block_expression (moo_t* moo)
{
colon_loc = moo->c->tok.loc;
/* block temporary variables */
/* block temporary variables - argument to blocks */
do
{
GET_TOKEN (moo);

View File

@ -89,10 +89,10 @@
# define LOG_MASK_INST (MOO_LOG_IC | MOO_LOG_MNEMONIC)
/* TODO: for send_message, display the method name. or include the method name before 'ip' */
# define LOG_INST_0(moo,fmt) MOO_LOG1(moo, LOG_MASK_INST, " %06zd " fmt "\n", fetched_instruction_pointer)
# define LOG_INST_1(moo,fmt,a1) MOO_LOG2(moo, LOG_MASK_INST, " %06zd " fmt "\n",fetched_instruction_pointer, a1)
# define LOG_INST_2(moo,fmt,a1,a2) MOO_LOG3(moo, LOG_MASK_INST, " %06zd " fmt "\n", fetched_instruction_pointer, a1, a2)
# define LOG_INST_3(moo,fmt,a1,a2,a3) MOO_LOG4(moo, LOG_MASK_INST, " %06zd " fmt "\n", fetched_instruction_pointer, a1, a2, a3)
# define LOG_INST_0(moo,fmt) MOO_LOG1(moo, LOG_MASK_INST, " %06zd " fmt "\n", (moo)->last_inst_pointer)
# define LOG_INST_1(moo,fmt,a1) MOO_LOG2(moo, LOG_MASK_INST, " %06zd " fmt "\n",(moo)->last_inst_pointer, a1)
# define LOG_INST_2(moo,fmt,a1,a2) MOO_LOG3(moo, LOG_MASK_INST, " %06zd " fmt "\n", (moo)->last_inst_pointer, a1, a2)
# define LOG_INST_3(moo,fmt,a1,a2,a3) MOO_LOG4(moo, LOG_MASK_INST, " %06zd " fmt "\n", (moo)->last_inst_pointer, a1, a2, a3)
#else
# define LOG_INST_0(moo,fmt)
# define LOG_INST_1(moo,fmt,a1)
@ -114,6 +114,7 @@ static int send_message_with_str (moo_t* moo, const moo_ooch_t* nameptr, moo_oow
/* ------------------------------------------------------------------------- */
static MOO_INLINE int vm_startup (moo_t* moo)
{
MOO_DEBUG0 (moo, "VM started up\n");
if (moo->vmprim.vm_startup (moo) <= -1) return -1;
moo->vmprim.vm_gettime (moo, &moo->exec_start_time); /* raw time. no adjustment */
return 0;
@ -123,6 +124,7 @@ static MOO_INLINE void vm_cleanup (moo_t* moo)
{
moo->vmprim.vm_gettime (moo, &moo->exec_end_time); /* raw time. no adjustment */
moo->vmprim.vm_cleanup (moo);
MOO_DEBUG0 (moo, "VM cleaned up\n");
}
static MOO_INLINE void vm_gettime (moo_t* moo, moo_ntime_t* now)
@ -556,7 +558,7 @@ static moo_oop_process_t signal_semaphore (moo_t* moo, moo_oop_semaphore_t sem)
/* [NOTE] no GC must occur as 'proc' isn't protected with moo_pushtmp(). */
/* detach a process from a semaphore waiting list and
/* detach a process from a semaphore's waiting list and
* make it runnable */
unchain_from_semaphore (moo, proc);
resume_process (moo, proc); /* TODO: error check */
@ -1130,30 +1132,97 @@ static int start_initial_process_and_context (moo_t* moo, const moo_oocs_t* objn
* send #main
*/
moo_oop_context_t ctx;
moo_oop_association_t ass;
moo_oop_method_t mth;
moo_oop_process_t proc;
#if defined(INVOKE_DIRECTLY)
moo_oop_association_t ass;
#else
moo_oop_t s1, s2;
#endif
moo_oow_t tmp_count = 0;
moo_oocs_t startup;
static moo_ooch_t str_startup[] = { 's', 't', 'a', 'r', 't', 'u', 'p' };
#if defined(INVOKE_DIRECTLY)
/* create a fake initial context. */
ctx = (moo_oop_context_t)moo_instantiate (moo, moo->_method_context, MOO_NULL, 0);
if (!ctx) return -1;
ass = moo_lookupsysdic (moo, objname);
if (!ass) return -1;
if (!ass || MOO_CLASSOF(moo, ass->value) != moo->_class)
{
MOO_DEBUG2 (moo, "Cannot find a class - %.*js", objname->len, objname->ptr);
return -1;
}
mth = find_method (moo, ass->value, mthname, 0);
if (!mth) return -1;
if (!mth)
{
MOO_DEBUG4 (moo, "Cannot find a method in %.*js - %.*js", objname->len, objname->ptr, mthname->len, mthname->ptr);
return -1;
}
if (MOO_OOP_TO_SMOOI(mth->tmpr_nargs) > 0)
{
/* this method expects more than 0 arguments.
* i can't use it as a start-up method.
TODO: overcome this problem
TODO: overcome this problem - accept parameters....
*/
MOO_DEBUG4 (moo, "Arguments not supported for a startup method - %.*js>>%.*js", objname->len, objname->ptr, mthname->len, mthname->ptr);
moo_seterrnum (moo, MOO_EINVAL);
return -1;
}
moo_pushtmp (moo, (moo_oop_t*)&mth); tmp_count++;
moo_pushtmp (moo, (moo_oop_t*)&ass); tmp_count++;
#else
startup.ptr = str_startup;
startup.len = 7;
mth = find_method (moo, (moo_oop_t)moo->_system, &startup, 0);
if (!mth)
{
MOO_DEBUG0 (moo, "Cannot find the startup method in the system class");
return -1;
}
if (MOO_OOP_TO_SMOOI(mth->tmpr_nargs) != 2)
{
MOO_DEBUG1 (moo, "Weird argument count %zd for a startup method - should be 2", MOO_OOP_TO_SMOOI(mth->tmpr_nargs));
moo_seterrnum (moo, MOO_EINVAL);
return -1;
}
/* TODO: check if it's variadic.... it should be. and accept more than 2... */
moo_pushtmp (moo, (moo_oop_t*)&mth); tmp_count++;
s1 = moo_makesymbol (moo, objname->ptr, objname->len);
if (!s1)
{
moo_poptmps (moo, tmp_count);
return -1;
}
moo_pushtmp (moo, (moo_oop_t*)&s1);
s2 = moo_makesymbol (moo, mthname->ptr, mthname->len);
if (!s2)
{
moo_poptmps (moo, tmp_count);
return -1;
}
moo_pushtmp (moo, (moo_oop_t*)&s2);
#endif
/* create a fake initial context. */
ctx = (moo_oop_context_t)moo_instantiate (moo, moo->_method_context, MOO_NULL, MOO_OOP_TO_SMOOI(mth->tmpr_nargs));
if (!ctx)
{
moo_poptmps (moo, tmp_count);
return -1;
}
moo_pushtmp (moo, (moo_oop_t*)&ctx); tmp_count++;
/* TODO: handle preamble */
/* the initial context starts the life of the entire VM
@ -1184,17 +1253,20 @@ TODO: overcome this problem
/* start_initial_process() calls the SWITCH_ACTIVE_CONTEXT() macro.
* the macro assumes a non-null value in moo->active_context.
* let's force set active_context to ctx directly. */
* let's forcefully set active_context to ctx directly. */
moo->active_context = ctx;
moo_pushtmp (moo, (moo_oop_t*)&ctx);
moo_pushtmp (moo, (moo_oop_t*)&mth);
moo_pushtmp (moo, (moo_oop_t*)&ass);
proc = start_initial_process (moo, ctx);
moo_poptmps (moo, 3);
moo_poptmps (moo, tmp_count); tmp_count = 0;
if (!proc) return -1;
#if defined(INVOKE_DIRECTLY)
MOO_STACK_PUSH (moo, ass->value); /* push the receiver - the object referenced by 'objname' */
#else
MOO_STACK_PUSH (moo, (moo_oop_t)moo->_system);
MOO_STACK_PUSH (moo, s1);
MOO_STACK_PUSH (moo, s2);
#endif
STORE_ACTIVE_SP (moo); /* moo->active_context->sp = MOO_SMOOI_TO_OOP(moo->sp) */
MOO_ASSERT (moo, moo->processor->active == proc);
@ -1203,7 +1275,11 @@ TODO: overcome this problem
MOO_ASSERT (moo, moo->active_context == ctx);
/* emulate the message sending */
#if defined(INVOKE_DIRECTLY)
return activate_new_method (moo, mth, 0);
#else
return activate_new_method (moo, mth, 2);
#endif
}
/* ------------------------------------------------------------------------- */
@ -1642,6 +1718,22 @@ static moo_pfrc_t pf_basic_at_put (moo_t* moo, moo_ooi_t nargs)
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_add_to_be_finalized (moo_t* moo, moo_ooi_t nargs)
{
/* TODO: check if it has already been added */
moo_regfinalizable (moo, MOO_STACK_GETRCV(moo,nargs));
MOO_STACK_SETRETTORCV (moo, nargs);
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_remove_to_be_finalized (moo_t* moo, moo_ooi_t nargs)
{
/* TODO: check if it has already been added */
moo_deregfinalizable (moo, MOO_STACK_GETRCV(moo,nargs));
MOO_STACK_SETRETTORCV (moo, nargs);
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_hash (moo_t* moo, moo_ooi_t nargs)
{
moo_oop_t rcv;
@ -2979,6 +3071,34 @@ static moo_pfrc_t pf_system_log (moo_t* moo, moo_ooi_t nargs)
return MOO_PF_SUCCESS;
}
static moo_pfrc_t pf_system_pop_collectable (moo_t* moo, moo_ooi_t nargs)
{
if (moo->collectable.first)
{
moo_collectable_t* first;
first = moo->collectable.first;
/* TODO: if it's already fininalized, delete it from collectable */
MOO_ASSERT (moo, MOO_OOP_IS_POINTER(first->oop));
MOO_ASSERT (moo, MOO_OBJ_GET_FLAGS_GCFIN(first->oop) & MOO_GCFIN_FINALIZABLE);
MOO_STACK_SETRET (moo, nargs, first->oop);
MOO_OBJ_SET_FLAGS_GCFIN (first->oop, MOO_OBJ_GET_FLAGS_GCFIN(first->oop) | MOO_GCFIN_FINALIZED);
MOO_DEBUG1 (moo, "POPPING FINALIZABLE...%O\n", first->oop);
MOO_DELETE_FROM_LIST (&moo->collectable, first);
moo_freemem (moo, first);
MOO_DEBUG1 (moo, "POPPED FINALIZABLE...%p\n", moo->collectable.first);
}
else
{
MOO_STACK_SETRETTOERROR (moo, nargs, MOO_ENOENT);
}
return MOO_PF_SUCCESS;
}
static MOO_INLINE moo_pfrc_t _system_alloc (moo_t* moo, moo_ooi_t nargs, int clear)
{
moo_oop_t tmp;
@ -3209,7 +3329,6 @@ static MOO_INLINE int _store_raw_uint (moo_t* moo, moo_uint8_t* rawptr, moo_oow_
int n;
moo_oow_t w, max;
if ((n = moo_inttooow (moo, voop, &w)) <= 0)
{
if (n <= -1) moo_seterrnum (moo, MOO_ERANGE); /* negative number */
@ -3793,6 +3912,7 @@ static pf_t pftab[] =
{ "_integer_ge", { pf_integer_ge, 1, 1 } },
{ "_integer_inttostr", { pf_integer_inttostr, 1, 1 } },
{ "Apex_addToBeFinalized", { pf_add_to_be_finalized, 0, 0 } },
{ "Apex__basicNew", { pf_basic_new, 0, 0 } },
{ "Apex__basicNew:", { pf_basic_new, 1, 1 } },
{ "Apex__basicSize", { pf_basic_size, 0, 0 } },
@ -3800,6 +3920,7 @@ static pf_t pftab[] =
{ "Apex_basicNew:", { pf_basic_new, 1, 1 } },
{ "Apex_basicSize", { pf_basic_size, 0, 0 } },
{ "Apex_class", { pf_class, 0, 0 } },
{ "Apex_removeToBeFinalized", { pf_remove_to_be_finalized, 0, 0 } },
{ "Character_asInteger", { pf_character_as_smooi, 0, 0 } },
@ -3851,6 +3972,7 @@ static pf_t pftab[] =
{ "System__getUint64", { pf_system_get_uint64, 2, 2 } },
{ "System__getUint8", { pf_system_get_uint8, 2, 2 } },
{ "System__malloc", { pf_system_malloc, 1, 1 } },
{ "System__popCollectable", { pf_system_pop_collectable, 0, 0 } },
{ "System__putInt8", { pf_system_put_int8, 3, 3 } },
{ "System__putInt16", { pf_system_put_int16, 3, 3 } },
{ "System__putInt32", { pf_system_put_int32, 3, 3 } },
@ -3893,7 +4015,8 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs)
moo_ooi_t /*sp,*/ stack_base;
#if defined(MOO_DEBUG_VM_EXEC)
moo_ooi_t fetched_instruction_pointer = 0; /* set it to a fake value */
/* set it to a fake value */
moo->last_instruction_pointer = 0;
#endif
preamble = MOO_OOP_TO_SMOOI(method->preamble);
@ -4441,7 +4564,8 @@ finalization:
return 1;
}
int moo_execute (moo_t* moo)
static int __execute (moo_t* moo)
{
moo_oob_t bcode;
moo_oow_t b1, b2;
@ -4449,15 +4573,6 @@ int moo_execute (moo_t* moo)
int unwind_protect;
moo_oop_context_t unwind_start;
moo_oop_context_t unwind_stop;
int vm_startup_called = 0;
#if defined(MOO_PROFILE_VM)
moo_uintmax_t inst_counter = 0;
#endif
#if defined(MOO_DEBUG_VM_EXEC)
moo_ooi_t fetched_instruction_pointer;
#endif
MOO_ASSERT (moo, moo->active_context != MOO_NULL);
@ -4468,24 +4583,22 @@ int moo_execute (moo_t* moo)
* these can be dirty if this function is called again esepcially after failure.
*/
if (vm_startup(moo) <= -1) goto oops;
vm_startup_called = 1;
moo->proc_switched = 0;
moo->abort_req = 0;
while (!moo->abort_req)
{
/*
if (moo->gc_finalization_pending)
switch_to_gc_process (xxxx);
else */
if (switch_process_if_needed(moo) == 0) break; /* no more runnable process */
#if defined(MOO_DEBUG_VM_EXEC)
fetched_instruction_pointer = moo->ip;
moo->last_inst_pointer = moo->ip;
#endif
FETCH_BYTE_CODE_TO (moo, bcode);
/*while (bcode == BCODE_NOOP) FETCH_BYTE_CODE_TO (moo, bcode);*/
#if defined(MOO_PROFILE_VM)
inst_counter++;
moo->inst_counter++;
#endif
switch (bcode)
@ -5006,7 +5119,7 @@ int moo_execute (moo_t* moo)
selector = (moo_oop_char_t)moo->active_method->slot[b2];
LOG_INST_3 (moo, "send_message%hs %zu @%zu", (((bcode >> 2) & 1)? "_to_super": ""), b1, b2);
if (send_message (moo, selector, ((bcode >> 2) & 1), b1) <= -1) goto oops;
if (send_message (moo, selector, ((bcode >> 2) & 1), b1) <= -1) return -1;
break;
}
@ -5110,7 +5223,7 @@ int moo_execute (moo_t* moo)
*/
MOO_STACK_PUSH (moo, (moo_oop_t)moo->_dictionary);
MOO_STACK_PUSH (moo, MOO_SMOOI_TO_OOP(b1));
if (send_message (moo, moo->dicnewsym, 0, 1) <= -1) goto oops;
if (send_message (moo, moo->dicnewsym, 0, 1) <= -1) return -1;
break;
case BCODE_POP_INTO_DICTIONARY:
@ -5124,7 +5237,7 @@ int moo_execute (moo_t* moo)
t2 = MOO_STACK_GETTOP(moo);
moo_putatdic (moo, (moo_oop_dic_t)t2, ((moo_oop_association_t)t1)->key, ((moo_oop_association_t)t1)->value);
*/
if (send_message (moo, moo->dicputassocsym, 0, 1) <= -1) goto oops;
if (send_message (moo, moo->dicputassocsym, 0, 1) <= -1) return -1;
break;
case BCODE_MAKE_ARRAY:
@ -5136,7 +5249,7 @@ int moo_execute (moo_t* moo)
/* create an empty array */
t = moo_instantiate (moo, moo->_array, MOO_NULL, b1);
if (!t) goto oops;
if (!t) return -1;
MOO_STACK_PUSH (moo, t); /* push the array created */
break;
@ -5312,7 +5425,7 @@ int moo_execute (moo_t* moo)
MOO_LOG0 (moo, MOO_LOG_IC | MOO_LOG_ERROR, "Error - cannot return from dead context\n");
moo_seterrnum (moo, MOO_EINTERN); /* TODO: can i make this error catchable at the moo level? */
goto oops;
return -1;
non_local_return_ok:
/*MOO_DEBUG2 (moo, "NON_LOCAL RETURN OK TO... %p %p\n", moo->active_context->origin, moo->active_context->origin->sender);*/
@ -5349,7 +5462,7 @@ int moo_execute (moo_t* moo)
MOO_STACK_PUSH (moo, (moo_oop_t)unwind_stop);
MOO_STACK_PUSH (moo, (moo_oop_t)return_value);
if (send_message_with_str (moo, fbm, 16, 0, 2) <= -1) goto oops;
if (send_message_with_str (moo, fbm, 16, 0, 2) <= -1) return -1;
}
else
{
@ -5376,9 +5489,14 @@ int moo_execute (moo_t* moo)
MOO_ASSERT (moo, moo->sp == 0);
if (moo->option.trait & MOO_AWAIT_PROCS)
{
terminate_process (moo, moo->processor->active);
}
else
{
/* graceful termination of the whole vm */
goto done;
}
/* TODO: store the return value to the VM register.
* the caller to moo_execute() can fetch it to return it to the system */
@ -5442,7 +5560,7 @@ int moo_execute (moo_t* moo)
* 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) goto oops;
if (!blkctx) return -1;
/* the long forward jump instruction has the format of
* 11000100 KKKKKKKK or 11000100 KKKKKKKK KKKKKKKK
@ -5499,7 +5617,7 @@ int moo_execute (moo_t* moo)
* 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) goto oops;
if (!blkctx) return -1;
/* get the receiver to the block copy message after block context instantiation
* not to get affected by potential GC */
@ -5566,20 +5684,37 @@ int moo_execute (moo_t* moo)
default:
MOO_LOG1 (moo, MOO_LOG_IC | MOO_LOG_FATAL, "Fatal error - unknown byte code 0x%zx\n", bcode);
moo_seterrnum (moo, MOO_EINTERN);
goto oops;
return -1;
}
}
done:
vm_cleanup (moo);
#if defined(MOO_PROFILE_VM)
MOO_LOG1 (moo, MOO_LOG_IC | MOO_LOG_INFO, "TOTAL_INST_COUTNER = %zu\n", inst_counter);
#endif
return 0;
}
oops:
if (vm_startup_called) vm_cleanup (moo);
return -1;
int moo_execute (moo_t* moo)
{
int n;
#if defined(MOO_PROFILE_VM)
moo->inst_counter = 0;
#endif
if (vm_startup(moo) <= -1) return -1;
moo->proc_switched = 0;
moo->abort_req = 0;
n = __execute (moo);
vm_cleanup (moo);
#if defined(MOO_PROFILE_VM)
MOO_LOG1 (moo, MOO_LOG_IC | MOO_LOG_INFO, "TOTAL_INST_COUTNER = %zu\n", moo->inst_counter);
#endif
return n;
}
void moo_abort (moo_t* moo)

View File

@ -117,6 +117,9 @@ static kernel_class_info_t kernel_classes[] =
{ 6, { 'S','y','s','t','e','m' }, MOO_OFFSETOF(moo_t, _system) },
};
static void move_finalizable_objects (moo_t* moo);
/* -----------------------------------------------------------------------
* BOOTSTRAPPER
* ----------------------------------------------------------------------- */
@ -701,6 +704,11 @@ void moo_gc (moo_t* moo)
ptr = (moo_uint8_t*) MOO_ALIGN ((moo_uintptr_t)moo->newheap->base, MOO_SIZEOF(moo_oop_t));
ptr = scan_new_heap (moo, ptr);
/* FINALIZATION */
move_finalizable_objects (moo);
ptr = scan_new_heap (moo, ptr);
/* END FINALIZATION */
/* traverse the symbol table for unreferenced symbols.
* if the symbol has not moved to the new heap, the symbol
* is not referenced by any other objects than the symbol
@ -809,3 +817,97 @@ moo_oop_t moo_shallowcopy (moo_t* moo, moo_oop_t oop)
return oop;
}
int moo_regfinalizable (moo_t* moo, moo_oop_t oop)
{
moo_collectable_t* x;
MOO_DEBUG1 (moo, "ADDING FINALIZABLE... %O\n", oop);
if (!MOO_OOP_IS_POINTER(oop) ||
(MOO_OBJ_GET_FLAGS_GCFIN(oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)))
{
moo_seterrnum (moo, MOO_EINVAL);
return -1;
}
x = moo_allocmem (moo, MOO_SIZEOF(*x));
if (!x) return -1;
MOO_OBJ_SET_FLAGS_GCFIN (oop, MOO_GCFIN_FINALIZABLE);
x->oop = oop;
MOO_APPEND_TO_LIST (&moo->finalizable, x);
MOO_DEBUG1 (moo, "ADDED FINALIZABLE... %O\n", oop);
return 0;
}
int moo_deregfinalizable (moo_t* moo, moo_oop_t oop)
{
moo_collectable_t* x;
if (!MOO_OOP_IS_POINTER(oop) ||
((MOO_OBJ_GET_FLAGS_GCFIN(oop) & (MOO_GCFIN_FINALIZABLE | MOO_GCFIN_FINALIZED)) != MOO_GCFIN_FINALIZABLE))
{
moo_seterrnum (moo, MOO_EINVAL);
return -1;
}
x = moo->finalizable.first;
while (x)
{
if (x->oop == oop)
{
/* TODO: do i need to clear other flags like GC */
MOO_OBJ_SET_FLAGS_GCFIN(oop, (MOO_OBJ_GET_FLAGS_GCFIN(oop) & ~MOO_GCFIN_FINALIZABLE));
MOO_DELETE_FROM_LIST (&moo->finalizable, x);
return 0;
}
}
moo_seterrnum (moo, MOO_ENOENT);
return -1;
}
static void move_finalizable_objects (moo_t* moo)
{
moo_collectable_t* x, * y;
for (x = moo->collectable.first; x; x = x->next)
{
x->oop = moo_moveoop (moo, x->oop);
}
for (x = moo->finalizable.first; x; )
{
y = x->next;
if (!MOO_OBJ_GET_FLAGS_MOVED(x->oop))
{
/* TODO: if already finalized, don't move, don't add to collectable
if (MOVE_OBJ_GET_FLAGS_FINALIZED(x->oop)) continue;
* */
x->oop = moo_moveoop (moo, x->oop);
/* it's almost collectable. but don't collect it yet.
* if garbages consist of finalizable objects only, GC should fail miserably */
/* remove it from the finalizable list */
MOO_DELETE_FROM_LIST (&moo->finalizable, x);
/* add it to the collectable list */
MOO_APPEND_TO_LIST (&moo->collectable, x);
//signal_semaphore (moo, moo->collectable_semaphore);
}
else
{
x->oop = moo_moveoop (moo, x->oop);
}
x = y;
}
}

View File

@ -1106,6 +1106,13 @@ moo_oop_nsdic_t moo_makensdic (
moo_oow_t size
);
/* ========================================================================= */
/* gc.c */
/* ========================================================================= */
int moo_regfinalizable (moo_t* moo, moo_oop_t oop);
int moo_deregfinalizable (moo_t* moo, moo_oop_t oop);
/* ========================================================================= */
/* proc.c */
/* ========================================================================= */

View File

@ -29,6 +29,34 @@
#include "moo-cmn.h"
/* -----------------------------------------------------------------------
* DOUBLY LINKED LIST MACROS
* ----------------------------------------------------------------------- */
#define MOO_APPEND_TO_LIST(list, node) do { \
(node)->next = MOO_NULL; \
(node)->prev = (list)->last; \
if ((list)->first) (list)->last->next = (node); \
else (list)->first = (node); \
(list)->last = (node); \
} while(0)
#define MOO_PREPPEND_TO_LIST(list, node) do { \
(node)->prev = MOO_NULL; \
(node)->next = (list)->first; \
if ((list)->last) (list)->first->prev = (node); \
else (list)->last = (node); \
(list)->first = (node); \
} while(0)
#define MOO_DELETE_FROM_LIST(list, node) do { \
if ((node)->prev) (node)->prev->next = (node)->next; \
else (list)->first = (node)->next; \
if ((node)->next) (node)->next->prev = (node)->prev; \
else (list)->last = (node)->prev; \
} while(0)
#if defined(__cplusplus)
extern "C" {
#endif

View File

@ -311,6 +311,13 @@ enum moo_obj_type_t
};
typedef enum moo_obj_type_t moo_obj_type_t;
enum moo_gcfin_t
{
MOO_GCFIN_FINALIZABLE = (1 << 0),
MOO_GCFIN_FINALIZED = (1 << 1)
};
typedef enum moo_gcfin_t moo_gcfin_t;
/* =========================================================================
* Object header structure
*
@ -330,6 +337,7 @@ typedef enum moo_obj_type_t moo_obj_type_t;
* moved: 0 or 1. used by GC. internal use only.
* ngc: 0 or 1, used by GC. internal use only.
* rdonly: 0 or 1. indicates that an object is immutable.
* gcfin: represents finalzation state.
* trailer: 0 or 1. indicates that there are trailing bytes
* after the object payload. internal use only.
*
@ -365,6 +373,7 @@ typedef enum moo_obj_type_t moo_obj_type_t;
#define MOO_OBJ_FLAGS_MOVED_BITS 1
#define MOO_OBJ_FLAGS_NGC_BITS 1
#define MOO_OBJ_FLAGS_RDONLY_BITS 1
#define MOO_OBJ_FLAGS_GCFIN_BITS 2
#define MOO_OBJ_FLAGS_TRAILER_BITS 1
#define MOO_OBJ_FLAGS_TYPE_SHIFT (MOO_OBJ_FLAGS_UNIT_BITS + MOO_OBJ_FLAGS_UNIT_SHIFT)
@ -373,7 +382,8 @@ typedef enum moo_obj_type_t moo_obj_type_t;
#define MOO_OBJ_FLAGS_KERNEL_SHIFT (MOO_OBJ_FLAGS_MOVED_BITS + MOO_OBJ_FLAGS_MOVED_SHIFT)
#define MOO_OBJ_FLAGS_MOVED_SHIFT (MOO_OBJ_FLAGS_NGC_BITS + MOO_OBJ_FLAGS_NGC_SHIFT)
#define MOO_OBJ_FLAGS_NGC_SHIFT (MOO_OBJ_FLAGS_RDONLY_BITS + MOO_OBJ_FLAGS_RDONLY_SHIFT)
#define MOO_OBJ_FLAGS_RDONLY_SHIFT (MOO_OBJ_FLAGS_TRAILER_BITS + MOO_OBJ_FLAGS_TRAILER_SHIFT)
#define MOO_OBJ_FLAGS_RDONLY_SHIFT (MOO_OBJ_FLAGS_GCFIN_BITS + MOO_OBJ_FLAGS_GCFIN_SHIFT)
#define MOO_OBJ_FLAGS_GCFIN_SHIFT (MOO_OBJ_FLAGS_TRAILER_BITS + MOO_OBJ_FLAGS_TRAILER_SHIFT)
#define MOO_OBJ_FLAGS_TRAILER_SHIFT (0)
#define MOO_OBJ_GET_FLAGS_TYPE(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TYPE_SHIFT, MOO_OBJ_FLAGS_TYPE_BITS)
@ -383,6 +393,7 @@ typedef enum moo_obj_type_t moo_obj_type_t;
#define MOO_OBJ_GET_FLAGS_MOVED(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_MOVED_SHIFT, MOO_OBJ_FLAGS_MOVED_BITS)
#define MOO_OBJ_GET_FLAGS_NGC(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_NGC_SHIFT, MOO_OBJ_FLAGS_NGC_BITS)
#define MOO_OBJ_GET_FLAGS_RDONLY(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_RDONLY_SHIFT, MOO_OBJ_FLAGS_RDONLY_BITS)
#define MOO_OBJ_GET_FLAGS_GCFIN(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_GCFIN_SHIFT, MOO_OBJ_FLAGS_GCFIN_BITS)
#define MOO_OBJ_GET_FLAGS_TRAILER(oop) MOO_GETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TRAILER_SHIFT, MOO_OBJ_FLAGS_TRAILER_BITS)
#define MOO_OBJ_SET_FLAGS_TYPE(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TYPE_SHIFT, MOO_OBJ_FLAGS_TYPE_BITS, v)
@ -392,6 +403,7 @@ typedef enum moo_obj_type_t moo_obj_type_t;
#define MOO_OBJ_SET_FLAGS_MOVED(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_MOVED_SHIFT, MOO_OBJ_FLAGS_MOVED_BITS, v)
#define MOO_OBJ_SET_FLAGS_NGC(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_NGC_SHIFT, MOO_OBJ_FLAGS_NGC_BITS, v)
#define MOO_OBJ_SET_FLAGS_RDONLY(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_RDONLY_SHIFT, MOO_OBJ_FLAGS_RDONLY_BITS, v)
#define MOO_OBJ_SET_FLAGS_GCFIN(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_GCFIN_SHIFT, MOO_OBJ_FLAGS_GCFIN_BITS, v)
#define MOO_OBJ_SET_FLAGS_TRAILER(oop,v) MOO_SETBITS(moo_oow_t, (oop)->_flags, MOO_OBJ_FLAGS_TRAILER_SHIFT, MOO_OBJ_FLAGS_TRAILER_BITS, v)
#define MOO_OBJ_GET_SIZE(oop) ((oop)->_size)
@ -989,6 +1001,14 @@ struct moo_sbuf_t
};
typedef struct moo_sbuf_t moo_sbuf_t;
typedef struct moo_collectable_t moo_collectable_t;
struct moo_collectable_t
{
moo_oop_t oop;
moo_collectable_t* prev;
moo_collectable_t* next;
};
/* special callback to be called for trailer */
typedef void (*moo_trgc_t) (moo_t* moo, moo_oop_t obj);
@ -1156,6 +1176,21 @@ struct moo_t
moo_sbuf_t sbuf[64];
struct
{
moo_collectable_t* first;
moo_collectable_t* last;
} collectable;
struct
{
moo_collectable_t* first;
moo_collectable_t* last;
} finalizable;
moo_uintmax_t inst_counter;
moo_ooi_t last_inst_pointer;
#if defined(MOO_INCLUDE_COMPILER)
moo_compiler_t* c;
#endif

View File

@ -163,6 +163,7 @@ oops:
static moo_pfrc_t pf_close_display (moo_t* moo, moo_ooi_t nargs)
{
oop_x11_t x11;
x11_trailer_t* tr;
// TODO: CHECK if the receiver is an X11 object
@ -174,6 +175,14 @@ static moo_pfrc_t pf_close_display (moo_t* moo, moo_ooi_t nargs)
x11->display = moo->_nil;
}
tr = moo_getobjtrailer (moo, MOO_STACK_GETRCV(moo,nargs), MOO_NULL);
if (tr->event)
{
moo_freemem (moo, tr->event);
tr->event = MOO_NULL;
}
MOO_STACK_SETRETTORCV (moo, nargs);
return MOO_PF_SUCCESS;
}