diff --git a/moo/kernel/Apex.moo b/moo/kernel/Apex.moo index 5e2dc3d..d38d96e 100644 --- a/moo/kernel/Apex.moo +++ b/moo/kernel/Apex.moo @@ -130,6 +130,12 @@ extend Apex else { self primitiveFailed } } + (* ------------------------------------------------------------------ + * FINALIZATION SUPPORT + * ------------------------------------------------------------------ *) + method(#dual,#primitive) addToBeFinalized. + ##method(#dual,#primitive) removeToBeFinalized. + (* ------------------------------------------------------------------ * HASHING * ------------------------------------------------------------------ *) diff --git a/moo/kernel/System.moo b/moo/kernel/System.moo index ec3ce33..6eba8ce 100644 --- a/moo/kernel/System.moo +++ b/moo/kernel/System.moo @@ -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 diff --git a/moo/kernel/X11.moo b/moo/kernel/X11.moo index ce42503..3eca5b9 100644 --- a/moo/kernel/X11.moo +++ b/moo/kernel/X11.moo @@ -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 diff --git a/moo/lib/comp.c b/moo/lib/comp.c index d46ee80..10d70e7 100644 --- a/moo/lib/comp.c +++ b/moo/lib/comp.c @@ -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); diff --git a/moo/lib/exec.c b/moo/lib/exec.c index cf9a09e..c806256 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -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; - /* create a fake initial context. */ - ctx = (moo_oop_context_t)moo_instantiate (moo, moo->_method_context, MOO_NULL, 0); - if (!ctx) return -1; + moo_oocs_t startup; + static moo_ooch_t str_startup[] = { 's', 't', 'a', 'r', 't', 'u', 'p' }; + +#if defined(INVOKE_DIRECTLY) + 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; @@ -3208,7 +3328,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) { @@ -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) diff --git a/moo/lib/gc.c b/moo/lib/gc.c index b84ded1..456f84e 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -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; + } +} diff --git a/moo/lib/moo-prv.h b/moo/lib/moo-prv.h index aee85eb..27f1dbf 100644 --- a/moo/lib/moo-prv.h +++ b/moo/lib/moo-prv.h @@ -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 */ /* ========================================================================= */ diff --git a/moo/lib/moo-utl.h b/moo/lib/moo-utl.h index f97f63f..b4082b9 100644 --- a/moo/lib/moo-utl.h +++ b/moo/lib/moo-utl.h @@ -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 diff --git a/moo/lib/moo.h b/moo/lib/moo.h index 721334f..3e22491 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -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. * @@ -358,14 +366,15 @@ typedef enum moo_obj_type_t moo_obj_type_t; * size calculation and the access to the payload fields become more complex. * Therefore, i've dropped the idea. * ========================================================================= */ -#define MOO_OBJ_FLAGS_TYPE_BITS 6 -#define MOO_OBJ_FLAGS_UNIT_BITS 5 -#define MOO_OBJ_FLAGS_EXTRA_BITS 1 -#define MOO_OBJ_FLAGS_KERNEL_BITS 2 -#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_TRAILER_BITS 1 +#define MOO_OBJ_FLAGS_TYPE_BITS 6 +#define MOO_OBJ_FLAGS_UNIT_BITS 5 +#define MOO_OBJ_FLAGS_EXTRA_BITS 1 +#define MOO_OBJ_FLAGS_KERNEL_BITS 2 +#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) #define MOO_OBJ_FLAGS_UNIT_SHIFT (MOO_OBJ_FLAGS_EXTRA_BITS + MOO_OBJ_FLAGS_EXTRA_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 diff --git a/moo/mod/x11.c b/moo/mod/x11.c index 1cc83b7..acca5d0 100644 --- a/moo/mod/x11.c +++ b/moo/mod/x11.c @@ -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; }