/* Translation rules for exception handling code, from Cforall to C. * * Reminder: This is not final. Besides names and things it is also going very * much for correctness and simplisity over efficiency. * * 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; // Will have to be availibe to user. Consider new name. Requires tagged types. forall(dtype parent | tagged(parent), dtype child | tagged(child)) parent *dynamic_cast(child *); void __throw_terminate(exception except) __attribute__((noreturn)); void __rethrow_terminate() __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); }; void __try_resume_cleanup(struct __try_resume_node * node); 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); // Rethrows (inside matching handlers): "Cforall" throw; resume; "C" __rethrow_terminate(); return false; // 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) { { if (dynamic_cast__SomeException(except)) { return 1; } } { OtherException err; if ( (err = dynamic_cast__OtherException(except)) && err.priority > 3) { return 2; } } 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 handle1(exception except) { { if (dynamic_cast__SomeException(except)) { fiddleThing(); return true; } } { OtherException err; if ( ( err = dynamic_cast__OtherException(except) ) && err.priority > 3) { twiddleWidget(); return true; } } return false; } struct __try_resume_node data = {.next = stack.except.top_resume, .try_to_handle = handle1}; 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(); } } } // Resume + Finally: "Cforall" void try_resume_finally() { try { insideTry(); } catch resume (SomeException) { fiddleThing(); } finally { twiddleWidget(); } } "C" void try_resume_finally() { { void finally1() { twiddleWidget(); } bool handle1(exception except) { { if (dynamic_cast__SomeException(except)) { fiddleThing(); return true; } } return false; } struct __cleanup_hook generated_name __attribute__((cleanup(finally1))); struct __try_resume_node data = {.next = stack.except.top_resume, .try_to_handle = handle1}; stack.except.top_resume = &data; struct __cleanup_hook generated_name __attribute__((cleanup(__try_resume_cleanup))); } } // Terminate + Resume + Finally: "Cforall" void try_all() { try { insideTry(); } catch (SomeException) { fiddleThing(); } catch resume (OtherException) { twiddleWidget(); } finally { twiddleWidget(); } } "C" void try_all() { { bool handle1() { { if (dynamic_cast__OtherException(except)) { twiddleWidget(); return true; } } return false; } void try1 () { struct __try_resume_node generated_name = {.next = stack.except.top_resume, .try_to_handle = handle1} __attribute__((cleanup(__try_resume_cleanup))); stack.except.top_resume = &data; 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; } void finally1() { twiddleWidget(); } struct __cleanup_hook generated_name __attribute__((cleanup(finally1))); __try_terminate(try1, catch1, match1); } }