/* Searches for a handler of the specified category, relative to the given * starting frame, searching according to the chosen mode. */ static LocatedHandler search_for_handler_from(MVMThreadContext *tc, MVMFrame *f, MVMuint8 mode, MVMuint32 cat) { LocatedHandler lh; lh.frame = NULL; lh.handler = NULL; if (mode == MVM_EX_THROW_LEXOTIC) { while (f != NULL) { lh = search_for_handler_from(tc, f, MVM_EX_THROW_LEX, cat); if (lh.frame != NULL) return lh; f = f->caller; } } else { while (f != NULL) { MVMFrameHandler *h = search_frame_handlers(tc, f, cat); if (h != NULL) { lh.frame = f; lh.handler = h; return lh; } if (mode == MVM_EX_THROW_DYN) { f = f->caller; } else { MVMFrame *f_maybe = f->outer; while (f_maybe != NULL && !in_caller_chain(tc, f_maybe)) f_maybe = f_maybe->outer; f = f_maybe; } } } return lh; }
/* Throws the specified exception object, taking the category from it. If * the handler resumes, the resumption result will be put into resume_result. * Leaves the interpreter in a state where it will next run the instruction of * the handler. If there is no handler, it will panic and exit with a backtrace. */ void MVM_exception_throwobj(MVMThreadContext *tc, MVMuint8 mode, MVMObject *exObj, MVMRegister *resume_result) { LocatedHandler lh; MVMException *ex; if (IS_CONCRETE(exObj) && REPR(exObj)->ID == MVM_REPR_ID_MVMException) ex = (MVMException *)exObj; else MVM_exception_throw_adhoc(tc, "Can only throw an exception object"); lh = search_for_handler_from(tc, tc->cur_frame, mode, ex->body.category); if (lh.frame == NULL) panic_unhandled_ex(tc, ex); run_handler(tc, lh, exObj); }
/* Searches for a handler of the specified category, relative to the given * starting frame, searching according to the chosen mode. */ static LocatedHandler search_for_handler_from(MVMThreadContext *tc, MVMFrame *f, MVMuint8 mode, MVMuint32 cat, MVMObject *payload) { LocatedHandler lh; lh.frame = NULL; lh.handler = NULL; lh.jit_handler = NULL; lh.handler_out_of_dynamic_scope = 0; switch (mode) { case MVM_EX_THROW_LEX_CALLER: f = f->caller; while (f && f->static_info->body.is_thunk) f = f->caller; /* And now we've gone down a caller, it's just lexical... */ case MVM_EX_THROW_LEX: while (f != NULL) { if (search_frame_handlers(tc, f, MVM_EX_THROW_LEX, cat, payload, &lh)) { if (in_caller_chain(tc, f)) lh.frame = f; else lh.handler_out_of_dynamic_scope = 1; return lh; } f = f->outer; } return lh; case MVM_EX_THROW_DYN: while (f != NULL) { if (search_frame_handlers(tc, f, mode, cat, payload, &lh)) { lh.frame = f; return lh; } f = f->caller; } return lh; case MVM_EX_THROW_LEXOTIC: while (f != NULL) { lh = search_for_handler_from(tc, f, MVM_EX_THROW_LEX, cat, payload); if (lh.frame != NULL) return lh; f = f->caller; } return lh; default: MVM_panic(1, "Unhandled exception throw mode %d", (int)mode); } }
/* Throws an exception by category, searching for a handler according to * the specified mode. If the handler resumes, the resumption result will * be put into resume_result. Leaves the interpreter in a state where it * will next run the instruction of the handler. If there is no handler, * it will panic and exit with a backtrace. */ void MVM_exception_throwcat(MVMThreadContext *tc, MVMuint8 mode, MVMuint32 cat, MVMRegister *resume_result) { LocatedHandler lh = search_for_handler_from(tc, tc->cur_frame, mode, cat); if (lh.frame == NULL) panic_unhandled_cat(tc, cat); run_handler(tc, lh, NULL); }
/* Searches for a handler of the specified category, relative to the given * starting frame, searching according to the chosen mode. */ static LocatedHandler search_for_handler_from(MVMThreadContext *tc, MVMFrame *f, MVMuint8 mode, MVMuint32 cat, MVMObject *payload) { MVMuint32 skip_first_inlinee = 0; LocatedHandler lh; lh.frame = NULL; lh.handler = NULL; lh.jit_handler = NULL; lh.handler_out_of_dynamic_scope = 0; switch (mode) { case MVM_EX_THROW_LEX_CALLER: skip_first_inlinee = 1; /* fallthrough */ case MVM_EX_THROW_LEX: { MVMint32 skip_all_inlinees = 0; while (f != NULL) { MVMFrame *outer_from_inlinee = NULL; if (search_frame_handlers_lex(tc, f, cat, payload, &lh, &skip_first_inlinee, skip_all_inlinees, &outer_from_inlinee)) { if (in_caller_chain(tc, f)) lh.frame = f; else lh.handler_out_of_dynamic_scope = 1; return lh; } if (skip_first_inlinee) { /* If this is still set, it means that the topmost frame * had no inlines, so we didn't already reach a chain of * outers to traverse. In this case, skip over any thunks * and continue the search. */ skip_first_inlinee = 0; f = f->caller; while (f && f->static_info->body.is_thunk) f = f->caller; } else { f = outer_from_inlinee ? outer_from_inlinee : f->outer; skip_all_inlinees = 1; } } return lh; } case MVM_EX_THROW_DYN: while (f != NULL) { if (search_frame_handlers_dyn(tc, f, cat, payload, &lh)) { lh.frame = f; return lh; } f = f->caller; } return lh; case MVM_EX_THROW_LEXOTIC: while (f != NULL) { lh = search_for_handler_from(tc, f, MVM_EX_THROW_LEX, cat, payload); if (lh.frame != NULL) return lh; f = f->caller; } return lh; default: MVM_panic(1, "Unhandled exception throw mode %d", (int)mode); } }