home *** CD-ROM | disk | FTP | other *** search
- /* seh.c: Structured exception handling in the compiler */
- #include "c.h"
- extern int getTvalValue(void);
- extern int getLevel(void);
-
- int hasExceptions=0;
- typedef struct tagExceptionInfo {
- struct tagExceptionInfo *Next;
- struct tagExceptionInfo *Previous;
- int l1;
- int l2;
- int l3;
- int value;
- int Flags;
- } ExceptionInfo;
-
- #define FINISHED 1
-
- static ExceptionInfo *pCurrentException=NULL;
- static ExceptionInfo *rootException=NULL;
- static int StaticDataEmitted = 0;
- /* Add another exception to the exception stack */
- ExceptionInfo *PushException(void)
- {
- ExceptionInfo *result;
-
- if (rootException == NULL) {
- rootException = (ExceptionInfo *)allocate(sizeof(ExceptionInfo),FUNC);
- result = rootException;
- memset(result,0,sizeof(ExceptionInfo));
- }
- else {
- /* search the last element */
- result = rootException;
- while (result->Next) {
- result = result->Next;
- }
- result->Next = (ExceptionInfo *)allocate(sizeof(ExceptionInfo),FUNC);
- memset(result->Next,0,sizeof(ExceptionInfo));
- result->Next->Previous = result;
- result = result->Next;
- }
- return(result);
- }
-
- /*
- No 'free' is done, since all the data is allocated in the FUNC heap
- that will be freed at the end of the function.
- */
- void PopException(void)
- {
- if (pCurrentException->Previous) {
- pCurrentException = pCurrentException->Previous;
- pCurrentException->Next = NULL;
- }
- else {
- rootException = NULL;
- pCurrentException = NULL;
- }
- }
-
- /*
- Utility function to add an assembler instruction to the code list.
- */
- static void AddAsm(char *str)
- {
- char *s;
-
- s = stringn(str,strlen(str));
- walk(0, 0, 0);
- code(Start); /* prevent unreachable code message */
- code(Asm);
- codelist->u.acode.code = s;
- codelist->u.acode.argv = NULL;
- }
-
- int doTry(void)
- {
- char tmpnom[25],tmpbuf[256];
- int l1,l2,l3;
- Symbol sl;
-
- /* 1. Push the exceptions stack by one */
- pCurrentException = PushException();
- /* Announce to the runtime that the static data is active
- within this block. Exceptions are enabled */
- AddAsm("\tmovl\t$0x0,-4(%ebp)");
- /* Update this global variable used in a few parts of lcc */
- hasExceptions++;
- /* Generate 3 labels:
- The first (label 1) marks the beginning of the first part
- of code that will be called to determine if the handler
- handles the exception or not.
- The second label will announce the start of the exception
- handler.
- The third announces the continuation of the normal code
- section
- */
- l1 = genlabel(1);
- sl = findlabel(l1);
- sl->ref = 1.0;
- sl->firstuse = sl->lastuse = StatementCount;
- l2 = genlabel(1);
- sl = findlabel(l2);
- sl->ref = 1.0;
- sl->firstuse = sl->lastuse = StatementCount;
- l3 = genlabel(1);
- sl = findlabel(l3);
- sl->ref = 1.0;
- sl->firstuse = sl->lastuse = StatementCount;
- pCurrentException->l1 = l1;
- pCurrentException->l2 = l2;
- pCurrentException->l3 = l3;
- /* The static data needed here should be emitted only once
- per compiled file
- */
- if (StaticDataEmitted == 0) {
- AddAsm("\t.data");
- sprintf(tmpbuf,"_$ExcepData:",tmpnom);
- AddAsm(tmpbuf);
- AddAsm("\t.long\t0xffffffff");
- sprintf(tmpbuf,"\t.long\t_$%d",l1);
- AddAsm(tmpbuf);
- sprintf(tmpbuf,"\t.long\t_$%d",l2);
- AddAsm(tmpbuf);
- AddAsm("\t.text");
- StaticDataEmitted = 1;
- }
- /* If we are in a nested exception block, the static data
- should point to the two labels that contain the two blocks
- of code to be called by the runtime
- */
- if (pCurrentException != rootException) {
- AddAsm("\tmovl\t$_$ExcepData,%eax");
- sprintf(tmpbuf,"\tmovl\t$_$%d,4(%%eax)",l1);
- AddAsm(tmpbuf);
- sprintf(tmpbuf,"\tmovl\t$_$%d,8(%%eax)",l2);
- AddAsm(tmpbuf);
- }
- return(1);
- }
-
- static void RestorePreviousException(void)
- {
- char tmpbuf[256];
-
- /*
- To avoid traps in the trap handlers, the runtime stores
- a continuation address at -4(%ebp). If we arrive here,
- everything is O.K. We have to restore then the zero at
- -4(%ebp) to go on normally
- */
- AddAsm("\tmovl\t$0x0,-4(%ebp)");
-
- AddAsm("\tmovl\t$_$ExcepData,%eax");
- sprintf(tmpbuf,"\tmovl\t$_$%d,4(%%eax)",pCurrentException->Previous->l1);
- AddAsm(tmpbuf);
- sprintf(tmpbuf,"\tmovl\t$_$%d,8(%%eax)",pCurrentException->Previous->l2);
- AddAsm(tmpbuf);
- }
-
- static void EmitFilterCode(void)
- {
- char tmpbuf[256];
-
- sprintf(tmpbuf,"_$%d:",pCurrentException->l1);
- AddAsm(tmpbuf);
- sprintf(tmpbuf,"\tmovl\t$%d,%%eax",pCurrentException->value);
- AddAsm(tmpbuf);
- AddAsm("\tret");
- }
-
- int FinishTryBlock(void)
- {
- char tmpbuf[256];
-
- if (pCurrentException->Flags & FINISHED) return(0);
- if (pCurrentException == rootException) {
- /* no exceptions are now active. Announce it to the
- runtime
- */
- AddAsm("\tmovl\t$-1,-4(%ebp)");
- }
- else {
- RestorePreviousException();
- }
- /* emit a jump to the end of the exception stuff */
- sprintf(tmpbuf,"\tjmp\t_$%d",pCurrentException->l3);
- AddAsm(tmpbuf);
- /* Avoid emitting this code again */
- pCurrentException->Flags |= FINISHED;
- return(1);
- }
-
- int doExcept(void)
- {
- char tmpbuf[20];
-
- /* No error treatment yet. Any syntax error leaves the parser
- in a mess...
- */
- t = gettok();
- if (t != '(') {
- error("Incorrect __except syntax\n");
- return(0);
- }
- t = gettok();
- if (t != ICON) {
- error("Incorrect __except expression!");
- return(0);
- }
- /* This should be actually an evaluation of an integer expression */
- pCurrentException->value = getTvalValue();
- t = gettok();
- if (t != ')') {
- error("missing ')' in __except expression");
- return(0);
- }
- FinishTryBlock();
- EmitFilterCode();
- /* Emit the label that marks the beginning of the exception handler
- code
- */
- sprintf(tmpbuf,"_$%d:",pCurrentException->l2);
- AddAsm(tmpbuf);
- /* Emit code to restore the stack when the exception
- handler is called
- */
- AddAsm("\tmovl\t-24(%ebp),%esp");
- /* Parse the exception handler code */
- t = gettok(); /* swallow the '{' */
- compound(0,NULL,getLevel());
- if (pCurrentException == rootException) {
- /*
- We are at the end of the top level exception block.
- Announce to the runtime there is no exception handler active
- */
- AddAsm("\tmovl\t$-1,-4(%ebp)");
- }
- else {
- RestorePreviousException();
- }
- /* Continuation of the normal code sequence */
- sprintf(tmpbuf,"_$%d:",pCurrentException->l3);
- AddAsm(tmpbuf);
- /* Clean up the exception stack, popping one level */
- PopException();
- return(1);
- }
-
- void ResetExceptions(void)
- {
- rootException = NULL;
- }
-