/* Translation rules for exception handling code, from Cforall to C. * * Note that these are not final. Names, syntax and the exact translation * will be updated. The first section is the shared definitions, not generated * by the local translations but used by the translated code. * * Most of these exist only after translation (in C code). The first (the * exception type) has to exist in Cforall code so that it can be used * directly in Cforall. The two __throw_* functions might have wrappers in * Cforall, but the underlying functions should probably be C. struct * stack_exception_data has to exist inside of the coroutine data structures * and so should be compiled as they are. */ // Currently it is a typedef for int, but later it will be a new type. typedef int exception; void __throw_terminate(exception except) __attribute__((noreturn)); void __throw_resume(exception except); void __try_terminate(void (*try_block)(), void (*catch_block)(int index, exception except), int (*match_block)(exception except)); struct __try_resume_node { struct __try_resume_node * next; bool (*try_to_handle)(exception except); }; struct __cleanup_hook {}; // An instance of the following must be paired with every stack. struct stack_exception_data { __try_resume_node * top_resume_data; // Other pointers may be required for re-resume. exception current_exception; int handler_index; }; // Translations: // Throws: "Cforall" throw exception_instance; resume exception_instance; "C" __throw_terminate(exception_instance); __throw_resume(exception_instance); // Termination Handlers: "Cforall" void try_terminate() { try { insideTry(); } catch (SomeException) { fiddleThing(); } catch (OtherException err ; err.priority > 3) { twiddleWidget(); } } "C" void try_terminate() { { void try1() { insideTry(); } // index is not nessasary, but should be much faster than going over // all the checks in if we can find a way to pass it in. void catch1(exception except, int index) { switch (index) { case 1: // if it is referenced in the handler, cast except. { fiddleThing(); } return; case 2: { twiddleWidget(); } return; default: // Error, should never be reached. } } int match1(exception except) { OtherException inner_except; if (dynamic_cast__SomeException(except)) { return 1; } else if ( (inner_except = dynamic_cast__OtherException(except)) && inner_except.priority > 3) { return 2; } else return 0; } __try_terminate(try1, catch1, match1); } } // Resumption Handlers: "Cforall" void try_resume() { try { insideTry(); } catch resume (SomeException) { fiddleThing(); } catch resume (OtherException err ; err.priority > 3) { twiddleWidget(); } } "C" void try_resume() { { bool catch1(exception except) { OtherException inner_except; if (dynamic_cast__SomeException(except)) { fiddleThing(); return true; } else if (dynamic_cast__OtherException(except) && inner_except.priority > 3) { twiddleWidget(); return true; } else { return false; } } struct __try_resume_node data = {.next = stack.except.top_resume, .try_to_handle = catch1}; stack.except.top_resume = &data; struct __cleanup_hook generated_name __attribute__((cleanup(__try_resume_cleanup))); { insideTry(); } } } // Finally Clause: "Cforall" void try_finally() { try { insideTry(); } finally { twiddleWidget(); } } "C" void try_finally() { { void finally1() { twiddleWidget(); } struct __cleanup_hook generated_name __attribute__((cleanup(finally1))); { insideTry(); } } } // Combining the Above: "Cforall" void try_all() { try { insideTry(); } catch (SomeException) { fiddleThing(); } catch resume (OtherException) { twiddleWidget(); } finally { twiddleWidget(); } } "C" void try_all() { { void try1 () { insideTry(); } void catch1(exception except, int index) { switch (index) { case 1: fiddleThing(); break; default: // Error if reached. } } int match1(exception except) { if (dynamic_cast__SomeException(except)) { return 1; } return 0; } bool catch2() { if (dynamic_cast__OtherException(except)) { twiddleWidget(); return true; } return false; } void finally1() { // (Finally, because of timing, also work for resume.) __try_resume_cleanup(); twiddleWidget(); } struct __try_resume_node generated_name = {.next = stack.except.top_resume, .try_to_handle = catch2}; stack.except.top_resume = &data; struct __cleanup_hook generated_name __attribute__((cleanup(finally1))); __try_terminate(try1, catch1, match1); } }