diff --git a/moo/kernel/test-002.moo b/moo/kernel/test-002.moo index abc6549..00f80a3 100644 --- a/moo/kernel/test-002.moo +++ b/moo/kernel/test-002.moo @@ -8,6 +8,53 @@ class MyObject(Object) { var(#class) a := 100. + var(#class) ensure_tester_v := 0. + + method(#class) test_quicksort: anArray + { + | quicksort | + quicksort := nil. + quicksort := [ :data :from :to | + (from < to) + ifTrue: [ | pivot index | + pivot := data at: from. + data swap: from with: to. + index := from. + from to: (to - 1) do: [ :each | + (data at: each) < pivot + ifTrue: [ + data swap: each with: index. + index := index + 1 + ] + ]. + + data swap: to with: index. + quicksort value: data value: from value: index - 1. + quicksort value: data value: index + 1 value: to + ]. + data + ]. + + ^(quicksort value: anArray value: 0 value: (anArray size - 1)) + } + + method(#class) test_on_do_with: dividend with: divisor + { + ## it returns 0 upon an exception otherwise, division result. + ^[ dividend div: divisor ] on: Exception do: [:ex | 0 ] + } + + method(#class) test_ensure_with: v + { + [ + [ Exception signal: "test ensure exception" ] ensure: [ self.ensure_tester_v := v ]. + ] on: Exception do: [:ex | /* do nothing */ ]. + } + + method(#class) test_ensure2_with: v + { + [ ^v * v ] ensure: [ self.ensure_tester_v := v ]. + } method(#class) proc1 { @@ -103,48 +150,27 @@ class MyObject(Object) } */ - method(#class) test_quicksort: anArray - { - | quicksort | - quicksort := nil. - quicksort := [ :data :from :to | - (from < to) - ifTrue: [ | pivot index | - pivot := data at: from. - data swap: from with: to. - index := from. - from to: (to - 1) do: [ :each | - (data at: each) < pivot - ifTrue: [ - data swap: each with: index. - index := index + 1 - ] - ]. - - data swap: to with: index. - quicksort value: data value: from value: index - 1. - quicksort value: data value: index + 1 value: to - ]. - data - ]. - - ^(quicksort value: anArray value: 0 value: (anArray size - 1)) - } - method(#class) main { | tc limit | tc := %( ## 0 - 4 + [ (self test_quicksort: #(7 12 3 20 5 8 2) copy) = #(2 3 5 7 8 12 20)], + [ (self test_quicksort: %(99, 12, 18, 7, 12, 3, 20, 5, 8, 2)) = #(2 3 5 7 8 12 12 18 20 99)], + [ (self test_on_do_with: 10 with: 2) == 5 ], + [ (self test_on_do_with: -10 with: 0) == 0 ], + [ self test_ensure_with: -20945. self.ensure_tester_v == -20945 ], + + ## 5-9 + [ ((self test_ensure2_with: 8) == 64) and: [self.ensure_tester_v == 8] ], [ self proc1 == 100 ], [ System sleepForSecs: 2. self proc1 == 200 ], [ self test_semaphore_heap == true ], [ self test_mutex = #(2000 6000) ], - ####[ self test_sem_sig ], - [ (self test_quicksort: #(7 12 3 20 5 8 2) copy) = #(2 3 5 7 8 12 20)], - [ (self test_quicksort: %(99, 12, 18, 7, 12, 3, 20, 5, 8, 2)) = #(2 3 5 7 8 12 12 18 20 99)], + ## 10-14 + ####[ self test_sem_sig ], [ System sleepForSecs: 2. self.a == 300 ] ## sleep before checking self.a to prevent different result depending on process switching frequency and speed ). diff --git a/moo/lib/exec.c b/moo/lib/exec.c index f560ba6..25aae01 100644 --- a/moo/lib/exec.c +++ b/moo/lib/exec.c @@ -136,7 +136,6 @@ static MOO_INLINE const char* proc_state_to_string (int state) static int delete_sem_from_sem_io_tuple (moo_t* moo, moo_oop_semaphore_t sem, int force); static void signal_io_semaphore (moo_t* moo, moo_ooi_t io_handle, moo_ooi_t mask); static int send_message (moo_t* moo, moo_oop_char_t selector, moo_ooi_t nargs, int to_super); -static int send_message_with_str (moo_t* moo, const moo_ooch_t* nameptr, moo_oow_t namelen, moo_ooi_t nargs); /* ------------------------------------------------------------------------- */ static MOO_INLINE int vm_startup (moo_t* moo) @@ -1686,58 +1685,6 @@ moo_oop_method_t moo_findmethodinclasschain (moo_t* moo, moo_oop_class_t _class, return mth; } -static MOO_INLINE moo_oop_method_t find_method_with_str (moo_t* moo, moo_oop_t receiver, const moo_oocs_t* message, int in_super) -{ - /* this function should be the same as moo_findmethod() mostly except cache management. - * this function can get removed if the callers create a symbol before look-up. TODO: << */ - moo_oop_class_t _class; - moo_oop_class_t c; - int mth_type; - moo_oop_method_t mth; - - _class = MOO_CLASSOF(moo, receiver); - if (_class == moo->_class) - { - /* receiver is a class object (an instance of Class) */ - c = (moo_oop_class_t)receiver; - mth_type = MOO_METHOD_CLASS; - } - else - { - /* receiver is not a class object. so take its class */ - c = _class; - mth_type = MOO_METHOD_INSTANCE; - } - MOO_ASSERT (moo, (moo_oop_t)c != moo->_nil); - - if (in_super) - { - MOO_ASSERT (moo, moo->active_method); - MOO_ASSERT (moo, moo->active_method->owner); - c = (moo_oop_class_t)((moo_oop_class_t)moo->active_method->owner)->superclass; - if ((moo_oop_t)c == moo->_nil) goto not_found; - /* c is nil if it reached the top of the hierarchy. - * otherwise c points to a class object */ - } - - /* [IMPORT] the method lookup logic should be the same as ciim_on_each_method() in comp.c */ - mth = find_method_in_class_chain(moo, c, mth_type, message); - if (mth) return mth; - -not_found: - if (_class == moo->_class) - { - /* the object is an instance of Class. find the method - * in an instance method dictionary of Class also */ - mth = find_method_in_class(moo, _class, MOO_METHOD_INSTANCE, message); - if (mth) return mth; - } - - MOO_LOG3 (moo, MOO_LOG_DEBUG, "Method '%.*js' not found in receiver %O\n", message->len, message->ptr, receiver); - moo_seterrbfmt (moo, MOO_ENOENT, "unable to find the method '%.*js' in %O", message->len, message->ptr, receiver); - return MOO_NULL; -} - moo_oop_method_t moo_findmethod (moo_t* moo, moo_oop_t receiver, moo_oop_char_t selector, int in_super) { moo_oop_class_t _class; @@ -1836,8 +1783,8 @@ not_found: } } - MOO_LOG3 (moo, MOO_LOG_DEBUG, "Method '%.*js' not found in receiver %O\n", message.len, message.ptr, receiver); - moo_seterrbfmt (moo, MOO_ENOENT, "unable to find the method '%.*js' in %O", message.len, message.ptr, receiver); + MOO_LOG4 (moo, MOO_LOG_DEBUG, "Method '%O>>%.*js' not found in receiver %O\n", _class, message.len, message.ptr, receiver); + moo_seterrbfmt (moo, MOO_ENOENT, "unable to find the method '%O>>%.*js' in %O", _class, message.len, message.ptr, receiver); return MOO_NULL; } @@ -1858,29 +1805,38 @@ static int start_initial_process_and_context (moo_t* moo, const moo_oocs_t* objn moo_oop_context_t ctx; moo_oop_method_t mth; moo_oop_process_t proc; + moo_oow_t tmp_count = 0; + moo_oop_t sym_startup; + #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' }; +#endif + #if defined(INVOKE_DIRECTLY) - ass = moo_lookupsysdic(moo, objname); if (!ass || MOO_CLASSOF(moo, ass->value) != moo->_class) { MOO_LOG2 (moo, MOO_LOG_DEBUG, "Cannot find a class '%.*js'", objname->len, objname->ptr); return -1; } + + sym_statup = moo_findsymbol(moo, mthname->ptr, mthname->len; + if (!sym_startup) + { + /* the method name should exist as a symbol in the system. + * otherwise, a method of such a name also doesn't exist */ + MOO_LOG4 (moo, MOO_LOG_DEBUG, "Cannot find a startup method symbol %.*js>>%.*js", objname->len, objname->ptr, mthname->len, mthname->ptr); + goto oops; + } - mth = moo_findmethowithstr(moo, ass->value, mthname, 0); + mth = moo_findmethod(moo, moo, ass->value, sym_startup, 0); if (!mth) { - MOO_LOG4 (moo, MOO_LOG_DEBUG, "Cannot find a method %.*js>>%.*js", objname->len, objname->ptr, mthname->len, mthname->ptr); + MOO_LOG4 (moo, MOO_LOG_DEBUG, "Cannot find a startup method %.*js>>%.*js", objname->len, objname->ptr, mthname->len, mthname->ptr); return -1; } @@ -1898,9 +1854,16 @@ TODO: overcome this problem - accept parameters.... moo_pushvolat (moo, (moo_oop_t*)&mth); tmp_count++; moo_pushvolat (moo, (moo_oop_t*)&ass); tmp_count++; #else - startup.ptr = str_startup; - startup.len = 7; - mth = find_method_with_str(moo, (moo_oop_t)moo->_system, &startup, 0); + sym_startup = moo_findsymbol(moo, str_startup, MOO_COUNTOF(str_startup)); + if (!sym_startup) + { + /* the method name should exist as a symbol in the system. + * otherwise, a method of such a name also doesn't exist */ + MOO_LOG0 (moo, MOO_LOG_DEBUG, "Cannot find the startup method name symbol in the system class"); + goto oops; + } + + mth = moo_findmethod(moo, (moo_oop_t)moo->_system, (moo_oop_char_t)sym_startup, 0); if (!mth) { MOO_LOG0 (moo, MOO_LOG_DEBUG, "Cannot find the startup method in the system class"); @@ -1932,7 +1895,6 @@ TODO: overcome this problem - accept parameters.... moo_pushvolat (moo, (moo_oop_t*)&ctx); tmp_count++; - /* TODO: handle preamble */ /* the initial context starts the life of the entire VM @@ -4402,11 +4364,6 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) #endif { /* no byte code to execute - invoke 'self primitiveFailed' */ - - static moo_ooch_t prim_fail_msg[] = { - 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', - 'F', 'a', 'i', 'l', 'e', 'd' - }; moo_oow_t i; if (stack_base != moo->sp - nargs - 1) @@ -4432,12 +4389,12 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) MOO_STACK_SET (moo, stack_base + 2, (moo_oop_t)method); /* send primitiveFailed to self */ - if (send_message_with_str (moo, prim_fail_msg, 15, nargs + 1) <= -1) return -1; + if (send_message(moo, moo->primitive_failed_sym, nargs + 1, 0) <= -1) return -1; } else { /* arrange to execute the method body */ - if (activate_new_method (moo, method, nargs) <= -1) return -1; + if (activate_new_method(moo, method, nargs) <= -1) return -1; } break; } @@ -4447,7 +4404,7 @@ static int start_method (moo_t* moo, moo_oop_method_t method, moo_oow_t nargs) preamble_code == MOO_METHOD_PREAMBLE_RETURN_CONTEXT || preamble_code == MOO_METHOD_PREAMBLE_EXCEPTION || preamble_code == MOO_METHOD_PREAMBLE_ENSURE); - if (activate_new_method (moo, method, nargs) <= -1) return -1; + if (activate_new_method(moo, method, nargs) <= -1) return -1; break; } @@ -4468,27 +4425,18 @@ static int send_message (moo_t* moo, moo_oop_char_t selector, moo_ooi_t nargs, i method = moo_findmethod(moo, receiver, selector, to_super); if (!method) - { - static moo_ooch_t fbm[] = { - 'd', 'o', 'e', 's', - 'N', 'o', 't', - 'U', 'n', 'd', 'e', 'r', 's', 't', 'a', 'n', 'd', ':' - }; - moo_oocs_t mthname; - - mthname.ptr = fbm; - mthname.len = 18; - - method = find_method_with_str(moo, receiver, &mthname, 0); + { + method = moo_findmethod(moo, receiver, moo->does_not_understand_sym, 0); if (!method) { /* this must not happen as long as doesNotUnderstand: is implemented under Apex. * this check should indicate a very serious internal problem */ MOO_LOG4 (moo, MOO_LOG_IC | MOO_LOG_FATAL, - "Fatal error - receiver [%O] of class [%O] does not understand a message [%.*js]\n", - receiver, MOO_CLASSOF(moo, receiver), mthname.len, mthname.ptr); - - moo_seterrnum (moo, MOO_EMSGSND); + "Fatal error - unable to find a fallback method [%O<<%.*js] for receiver [%O]\n", + MOO_CLASSOF(moo, receiver), MOO_OBJ_GET_SIZE(moo->does_not_understand_sym), MOO_OBJ_GET_CHAR_SLOT(moo->does_not_understand_sym), receiver); + + moo_seterrbfmt (moo, MOO_EMSGSND, "unable to find a fallback method - %O<<%.*js", + MOO_CLASSOF(moo, receiver), MOO_OBJ_GET_SIZE(moo->does_not_understand_sym), MOO_OBJ_GET_CHAR_SLOT(moo->does_not_understand_sym)); return -1; } else @@ -4503,30 +4451,7 @@ static int send_message (moo_t* moo, moo_oop_char_t selector, moo_ooi_t nargs, i } } - return start_method (moo, method, nargs); -} - -static int send_message_with_str (moo_t* moo, const moo_ooch_t* nameptr, moo_oow_t namelen, moo_ooi_t nargs) -{ - moo_oocs_t mthname; - moo_oop_t receiver; - moo_oop_method_t method; - - receiver = MOO_STACK_GET(moo, moo->sp - nargs); - - mthname.ptr = (moo_ooch_t*)nameptr; - mthname.len = namelen; - method = find_method_with_str(moo, receiver, &mthname, 0); - if (!method) - { - MOO_LOG4 (moo, MOO_LOG_IC | MOO_LOG_FATAL, - "Fatal error - receiver [%O] of class [%O] does not understand a private message [%.*js]\n", - receiver, MOO_CLASSOF(moo, receiver), mthname.len, mthname.ptr); - moo_seterrnum (moo, MOO_EMSGSND); - return -1; - } - - return start_method (moo, method, nargs); + return start_method(moo, method, nargs); } /* ------------------------------------------------------------------------- */ @@ -4935,16 +4860,12 @@ static MOO_INLINE int do_return (moo_t* moo, moo_oob_t bcode, moo_oop_t return_v if (unwind_protect) { - static moo_ooch_t fbm[] = { - 'u', 'n', 'w', 'i', 'n', 'd', 'T', 'o', ':', - 'r', 'e', 't', 'u', 'r', 'n', ':' - }; - + /* if ensure: is used over a non-local return, it should reach here. + * [^10] ensure: [...] */ MOO_STACK_PUSH (moo, (moo_oop_t)unwind_start); 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, 2) <= -1) return -1; + if (send_message(moo, moo->unwindto_return_sym, 2, 0) <= -1) return -1; } else { diff --git a/moo/lib/gc.c b/moo/lib/gc.c index c3c5ac5..39f05fb 100644 --- a/moo/lib/gc.c +++ b/moo/lib/gc.c @@ -566,7 +566,10 @@ static int ignite_3 (moo_t* moo) static moo_ooch_t str_processor[] = { 'P', 'r', 'o', 'c', 'e', 's', 's', 'o', 'r' }; static moo_ooch_t str_dicnew[] = { 'n', 'e', 'w', ':' }; static moo_ooch_t str_dicputassoc[] = { '_','_','p', 'u', 't', '_', 'a', 's', 's', 'o', 'c', ':' }; - + static moo_ooch_t str_does_not_understand[] = { 'd', 'o', 'e', 's', 'N', 'o', 't', 'U', 'n', 'd', 'e', 'r', 's', 't', 'a', 'n', 'd', ':' }; + static moo_ooch_t str_primitive_failed[] = { 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 'F', 'a', 'i', 'l', 'e', 'd' }; + static moo_ooch_t str_unwindto_return[] = { 'u', 'n', 'w', 'i', 'n', 'd', 'T', 'o', ':', 'r', 'e', 't', 'u', 'r', 'n', ':' }; + moo_oow_t i; moo_oop_t sym; moo_oop_class_t cls; @@ -603,6 +606,18 @@ static int ignite_3 (moo_t* moo) if (!sym) return -1; moo->dicputassocsym = (moo_oop_char_t)sym; + sym = moo_makesymbol(moo, str_does_not_understand, MOO_COUNTOF(str_does_not_understand)); + if (!sym) return -1; + moo->does_not_understand_sym = (moo_oop_char_t)sym; + + sym = moo_makesymbol(moo, str_primitive_failed, MOO_COUNTOF(str_primitive_failed)); + if (!sym) return -1; + moo->primitive_failed_sym = (moo_oop_char_t)sym; + + sym = moo_makesymbol(moo, str_unwindto_return, MOO_COUNTOF(str_unwindto_return)); + if (!sym) return -1; + moo->unwindto_return_sym = (moo_oop_char_t)sym; + return 0; } @@ -937,6 +952,9 @@ void moo_gc (moo_t* moo) moo->nil_process = (moo_oop_process_t)moo_moveoop(moo, (moo_oop_t)moo->nil_process); moo->dicnewsym = (moo_oop_char_t)moo_moveoop(moo, (moo_oop_t)moo->dicnewsym); moo->dicputassocsym = (moo_oop_char_t)moo_moveoop(moo, (moo_oop_t)moo->dicputassocsym); + moo->does_not_understand_sym = (moo_oop_char_t)moo_moveoop(moo, (moo_oop_t)moo->does_not_understand_sym); + moo->primitive_failed_sym = (moo_oop_char_t)moo_moveoop(moo, (moo_oop_t)moo->primitive_failed_sym); + moo->unwindto_return_sym = (moo_oop_char_t)moo_moveoop(moo, (moo_oop_t)moo->unwindto_return_sym); for (i = 0; i < moo->sem_list_count; i++) { diff --git a/moo/lib/moo.h b/moo/lib/moo.h index eb532c7..0a86d18 100644 --- a/moo/lib/moo.h +++ b/moo/lib/moo.h @@ -1491,7 +1491,11 @@ struct moo_t moo_oop_process_t nil_process; /* instance of Process */ moo_oop_char_t dicnewsym; /* symbol new: for dictionary */ moo_oop_char_t dicputassocsym; /* symbol put_assoc: for dictionary */ - + moo_oop_char_t does_not_understand_sym; /* symbol doesNotUnderstand: */ + moo_oop_char_t primitive_failed_sym; /* symbol primitiveFailed */ + moo_oop_char_t unwindto_return_sym; /* symbol unwindTo:return: */ + + /* pending asynchronous semaphores */ moo_oop_semaphore_t* sem_list; moo_oow_t sem_list_count; diff --git a/moo/lib/pf-basic.c b/moo/lib/pf-basic.c index 703e928..52cfbb2 100644 --- a/moo/lib/pf-basic.c +++ b/moo/lib/pf-basic.c @@ -809,7 +809,7 @@ moo_pfrc_t moo_pf_responds_to (moo_t* moo, moo_mod_t* mod, moo_ooi_t nargs) return MOO_PF_FAILURE; } - if (moo_findmethod(moo, rcv, selector, 0)) + if (moo_findmethod(moo, rcv, (moo_oop_char_t)selector, 0)) { MOO_STACK_SETRET (moo, nargs, moo->_true); }