static inline NORETURN void resume(unw_cursor_t* cursor, const uint8_t* landing_pad, int64_t switch_value, const ExcInfo* exc_data) { checkExcInfo(exc_data); assert(landing_pad); if (VERBOSITY("cxx_unwind") >= 4) printf(" * RESUMED: ip %p switch_value %ld\n", (const void*)landing_pad, (long)switch_value); if (0 != switch_value) { // The exception handler will call __cxa_begin_catch, which stops this timer and logs it. per_thread_resume_catch_timer.restart("resume_catch", 20); } else { // The cleanup code will call _Unwind_Resume, which will stop this timer and log it. // TODO: am I sure cleanup code can't raise exceptions? maybe have an assert! per_thread_cleanup_timer.restart("cleanup", 20); #ifndef NDEBUG in_cleanup_code = true; #endif } // set rax to pointer to exception object // set rdx to the switch_value (0 for cleanup, otherwise an index indicating which exception handler to use) // // NB. assumes x86-64. maybe I should use __builtin_eh_return_data_regno() here? // but then, need to translate into UNW_* values somehow. not clear how. check(unw_set_reg(cursor, UNW_X86_64_RAX, (unw_word_t)exc_data)); check(unw_set_reg(cursor, UNW_X86_64_RDX, switch_value)); // resume! check(unw_set_reg(cursor, UNW_REG_IP, (unw_word_t)landing_pad)); unw_resume(cursor); RELEASE_ASSERT(0, "unw_resume returned!"); }
extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(void*)) { static pyston::StatCounter num_cxa_throw("num_cxa_throw"); num_cxa_throw.log(); assert(!pyston::in_cleanup_code); assert(exc_obj); RELEASE_ASSERT(tinfo == &EXCINFO_TYPE_INFO, "can't throw a non-ExcInfo value! type info: %p", tinfo); if (VERBOSITY("cxx_unwind") >= 4) printf("***** __cxa_throw() *****\n"); pyston::ExcInfo* exc_data = (pyston::ExcInfo*)exc_obj; checkExcInfo(exc_data); ASSERT(!pyston::is_unwinding, "We don't support throwing exceptions in destructors!"); pyston::is_unwinding = true; #if STAT_TIMERS pyston::StatTimer::overrideCounter(unwinding_stattimer); #endif // let unwinding.cpp know we've started unwinding pyston::logException(exc_data); pyston::unwind(exc_data); }
// Takes the value that resume() sent us in RAX, and returns a pointer to the exception object actually thrown. In our // case, these are the same, and should always be &pyston::exception_ferry. extern "C" void* __cxa_begin_catch(void* exc_obj_in) noexcept { assert(exc_obj_in); pyston::us_unwind_resume_catch.log(pyston::per_thread_resume_catch_timer.end()); if (VERBOSITY("cxx_unwind") >= 4) printf("***** __cxa_begin_catch() *****\n"); pyston::ExcInfo* e = (pyston::ExcInfo*)exc_obj_in; checkExcInfo(e); return e; }
extern "C" void __cxa_throw(void* exc_obj, std::type_info* tinfo, void (*dtor)(void*)) { assert(!pyston::in_cleanup_code); assert(exc_obj); RELEASE_ASSERT(tinfo == &EXCINFO_TYPE_INFO, "can't throw a non-ExcInfo value! type info: %p", tinfo); if (VERBOSITY("cxx_unwind") >= 4) printf("***** __cxa_throw() *****\n"); pyston::ExcInfo* exc_data = (pyston::ExcInfo*)exc_obj; checkExcInfo(exc_data); #if STAT_TIMERS pyston::StatTimer::overrideCounter(unwinding_stattimer); #endif // let unwinding.cpp know we've started unwinding pyston::throwingException(pyston::getActivePythonUnwindSession()); pyston::unwind(exc_data); }
extern "C" void* __cxa_get_exception_ptr(void* exc_obj_in) noexcept { assert(exc_obj_in); pyston::ExcInfo* e = (pyston::ExcInfo*)exc_obj_in; checkExcInfo(e); return e; }
// The unwinder entry-point. static void unwind(ExcInfo* exc) { checkExcInfo(exc); unwind_loop(exc); // unwind_loop returned, couldn't find any handler. ruh-roh. panic(); }