Tim Peters wrote: <SNIP> > An internal PyExc_AttributeError isn't the same as a user-visible > AttributeError, though -- a class instance isn't created unless and until > PyErr_NormalizeException() gets called because the exception needs to be > made user-visible. If the latter never happens, setting and clearing > exceptions internally is pretty cheap (a pointer to the global > PyExc_AttributeError object is stuffed into the thread state). OTOH, almost > every call to a C API function has to test+branch for an error-return value, > and I've often wondered whether a setjmp/longjmp-based hack might allow for > cleaner and more optimizable code (hand-rolled "real exception handling"). > For some odd reason (maybe because of all the code touch-ups I did to Python/ast.c in the AST branch), the idea of doing exception handling in C using setjmp/longjmp really appealed to me. So, being a programmer with an itch that needed to be scratched, I came up with a possible solution. Even if the idea would work (which I don't know if it will just because I am not sure how thread-safe it is nor if the code will work; this was a mental exercise that doesn't compile because of casting of jmp_buf and such), I doubt it will ever be incorporated into Python just because it would require so much change to the C code. But hey, who knows. The basic idea is to keep a stack of jmp_buf points. They are pushed on to the stack when a chunk of code wants to handle an exception. The basic code is in the function try_except(); have an 'if' that calls a function that pushes on to the stack a new jmp_buf and register it in the conditional check. When an exception is raised a function is called (makejmp()) that pops the stack and jumps to the jmp_buf that is popped. Continue until the last item on the stack is reached which should be PyErr_NormalizeException() (I think that is the function that exposes an exception to Python code). I have no clue how much performance benefit/loss there would be from this, but code would be cleaner since you wouldn't have to do constant ``if (fxn() == NULL) return NULL;`` checks for raised exceptions. But in case anyone cares, here is the *very* rough C code: #include <stddef.h> #include <setjmp.h> /* Basically just a stack item */ typedef struct jmp_stack_item_struct { jmp_buf jmp_point; struct jmp_stack_item_struct *previous; } jmp_stack_item; /* Global stack of jmp points to exception handlers */ jmp_stack_item *jmp_stack; void try_except(void) { jmp_stack = NULL; /* try: */ if (!setjmp(allocjmp())) { ; } /* except: */ else { ; } } /* returning jmp_buf like this makes gcc unhappy since it is an array */ jmp_buf allocjmp(void) { /* malloc jmp_buf and put on top of stack */ /* return malloc'ed jmp_buf */ jmp_stack_item *new_jmp = (jmp_stack_item *) malloc(sizeof(jmp_stack_item)); if (!jmp_stack) { new_jmp->previous = NULL; } else { new_jmp->previous = jmp_stack; } jmp_stack = new_jmp; return new_jmp->jmp_point; } void raise(void) { /* Exception set; now call... */ makejmp(); } void makejmp(void) { jmp_stack_item *top_jmp = jmp_stack; jmp_buf jmp_to; if (!jmp_stack->previous) longjmp(jmp_stack->jmp_point, 1); else { memmove(jmp_to, top_jmp->jmp_point, sizeof(jmp_to)); jmp_stack = top_jmp->previous; free(top_jmp); longjmp(jmp_to, 1); } }
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4