Date: Sat, 9 Jan 1999 12:05:45 +0900 (JST) From: dcs@newsguy.com To: FreeBSD-gnats-submit@FreeBSD.ORG Subject: kern/9402: Loader does not support exception handling Message-ID: <199901090305.MAA00567@local.ocn.ne.jp>
next in thread | raw e-mail | index | archive | help
>Number: 9402 >Category: kern >Synopsis: Loader's builtin forth has no support for exception handling >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Fri Jan 8 19:10:01 PST 1999 >Closed-Date: >Last-Modified: >Originator: Daniel C. Sobral >Release: FreeBSD 3.0-CURRENT i386 >Organization: >Environment: Three stage boot's loader. >Description: Currently, loader has no set of words to deal with exception handling. This adds extra complexity to the operation of builtin words, if they are ever to return error codes (and may, in fact, preclude it). >How-To-Repeat: UTSL? >Fix: I propose ANS Forth standard's exception handling wordset. It is composed of the words CATCH and THROW. CATCH takes an xt, saves context and then acts like EXECUTE. There are two possible exits for CATCH. First, if, during xt's execution, a THROW is executed with a non-zero value passed, catch restores the context (this being at defined as, at least, the two stack pointers, though the fix below saves the entire FICL_VM structure, plus the FICL_STACK structures pointed by FICL_VM elements) and pushes the value passed to THROW on the stack. The stack contains precisely the number of cells as when CATCH was first executed, in the case. Second, if no THROW is executed, or all executed THROW's are passed 0, catch just push a 0 on the stack. In this case, CATCH acts just like "EXECUTE 0". Catch must be (and is) nestable. Pending the commit of this fix, further patches to actually make use of this feature on the loader will be submitted. Apply the following fix to sys/boot/ficl/words.c: --- sys/boot/ficl/words.c.orig Sat Jan 9 05:23:59 1999 +++ sys/boot/ficl/words.c Sat Jan 9 11:50:32 1999 @@ -4046,6 +4046,150 @@ return; } +/***************** freebsd added exception handling words *******************/ + +/* + * Catch, from ANS Forth standard. Installs a safety net, then EXECUTE + * the word in ToS. If an exception happens, restore the state to what + * it was before, and pushes the exception value on the stack. If not, + * push zero. + * + * Notice that Catch implements an inner interpreter. This is ugly, + * but given how ficl works, it cannot be helped. The problem is that + * colon definitions will be executed *after* the function returns, + * while "code" definitions will be executed immediately. I considered + * other solutions to this problem, but all of them shared the same + * basic problem (with added disadvantages): if ficl ever changes it's + * inner thread modus operandi, one would have to fix this word. + * + * More comments can be found throughout catch's code. + * + * Daniel C. Sobral Jan 09/1999 + */ + +static void catch(FICL_VM *pVM) +{ + int except; + jmp_buf vmState; + FICL_VM VM; + FICL_STACK pStack; + FICL_STACK rStack; + FICL_WORD *pFW; + IPTYPE exitIP; + + /* + * Get xt. + * We need this *before* we save the stack pointer, or + * we'll have to pop one element out of the stack after + * an exception. I prefer to get done with it up front. :-) + */ +#if FICL_ROBUST > 1 + vmCheckStack(pVM, 1, 0); +#endif + pFW = stackPopPtr(pVM->pStack); + + /* + * Save vm's state -- a catch will not back out environmental + * changes. + * + * We are *not* saving dictionary state, since it is + * global instead of per vm, and we are not saving + * stack contents, since we are not required to (and, + * thus, it would be useless). We save pVM, and pVM + * "stacks" (a structure containing general information + * about it, including the current stack pointer). + */ + memcpy((void*)&VM, (void*)pVM, sizeof(FICL_VM)); + memcpy((void*)&pStack, (void*)pVM->pStack, sizeof(FICL_STACK)); + memcpy((void*)&rStack, (void*)pVM->rStack, sizeof(FICL_STACK)); + + /* + * Give pVM a jmp_buf + */ + pVM->pState = &vmState; + + /* + * Safety net + */ + except = setjmp(vmState); + + /* + * And now, choose what to do depending on except. + */ + + /* Things having gone wrong... */ + if(except) { + /* Restore vm's state */ + memcpy((void*)pVM, (void*)&VM, sizeof(FICL_VM)); + memcpy((void*)pVM->pStack, (void*)&pStack, sizeof(FICL_STACK)); + memcpy((void*)pVM->rStack, (void*)&rStack, sizeof(FICL_STACK)); + + /* Push error */ + stackPushINT32(pVM->pStack, except); + + /* Things being ok... */ + } else { + /* + * We need to know when to exit the inner loop + * Colonp, the "code" for colon words, just pushes + * the word's IP onto the RP, and expect the inner + * interpreter to do the rest. Well, I'd rather have + * it done *before* I return from this function, + * losing the automatic variables I'm using to save + * state. Sure, I could save this on dynamic memory + * and save state on RP, or I could even implement + * the poor man's version of this word in Forth with + * sp@, sp!, rp@ and rp!, but we have a lot of state + * neatly tucked away in pVM, so why not save it? + */ + exitIP = pVM->ip; + + /* Execute the xt -- inline code for vmExecute */ + + pVM->runningWord = pFW; + pFW->code(pVM); + + /* + * Run the inner loop until we get back to exitIP + */ + for (; pVM->ip != exitIP;) { + pFW = *pVM->ip++; + + /* Inline code for vmExecute */ + pVM->runningWord = pFW; + pFW->code(pVM); + } + + + /* Restore just the setjmp vector */ + pVM->pState = VM.pState; + + /* Push 0 -- everything is ok */ + stackPushINT32(pVM->pStack, 0); + } +} + +/* + * Throw -- maybe vmThow already do what's required, but I don't really + * know what happens when you longjmp(buf, 0). From ANS Forth standard. + * + * Anyway, throw takes the ToS and, if that's different from zero, + * returns to the last executed catch context. Further throws will + * unstack previously executed "catches", in LIFO mode. + * + * Daniel C. Sobral Jan 09/1999 + */ + +static void throw(FICL_VM *pVM) +{ + int except; + + except = stackPopINT32(pVM->pStack); + + if (except) + vmThrow(pVM, except); +} + /************************* freebsd added I/O words **************************/ /* fopen - open a file and return new fd on stack. @@ -4382,6 +4526,8 @@ dictAppendWord(dp, "key?", keyQuestion, FW_DEFAULT); dictAppendWord(dp, "ms", ms, FW_DEFAULT); dictAppendWord(dp, "seconds", pseconds, FW_DEFAULT); + dictAppendWord(dp, "catch", catch, FW_DEFAULT); + dictAppendWord(dp, "throw", throw, FW_DEFAULT); /* ** Set CORE environment query values >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199901090305.MAA00567>