/* Looks through the handlers of a particular scope, and sees if one will * match what we're looking for. Returns 1 to it if so; if not, * returns 0. */ static MVMint32 search_frame_handlers(MVMThreadContext *tc, MVMFrame *f, MVMuint8 mode, MVMuint32 cat, MVMObject *payload, LocatedHandler *lh) { MVMuint32 i; if (f->spesh_cand && f->spesh_cand->jitcode && f->jit_entry_label) { MVMJitHandler *jhs = f->spesh_cand->jitcode->handlers; MVMFrameHandler *fhs = f->effective_handlers; MVMint32 num_handlers = f->spesh_cand->jitcode->num_handlers; void **labels = f->spesh_cand->jitcode->labels; void *cur_label = f->jit_entry_label; for (i = 0; i < num_handlers; i++) { if (mode == MVM_EX_THROW_LEX && fhs[i].inlined_and_not_lexical) continue; if (!handler_can_handle(f, &fhs[i], cat, payload)) continue; if (cur_label >= labels[jhs[i].start_label] && cur_label <= labels[jhs[i].end_label] && !in_handler_stack(tc, &fhs[i], f)) { lh->handler = &fhs[i]; lh->jit_handler = &jhs[i]; return 1; } } } else { MVMint32 num_handlers = f->spesh_cand ? f->spesh_cand->num_handlers : f->static_info->body.num_handlers; MVMint32 pc; if (f == tc->cur_frame) pc = (MVMuint32)(*tc->interp_cur_op - *tc->interp_bytecode_start); else pc = (MVMuint32)(f->return_address - f->effective_bytecode); for (i = 0; i < num_handlers; i++) { MVMFrameHandler *fh = &f->effective_handlers[i]; if (mode == MVM_EX_THROW_LEX && fh->inlined_and_not_lexical) continue; if (!handler_can_handle(f, fh, cat, payload)) continue; if (pc >= fh->start_offset && pc <= fh->end_offset && !in_handler_stack(tc, fh, f)) { lh->handler = fh; return 1; } } } return 0; }
/* Looks through the handlers of a particular frame, including inlines in * dynamic scope, and sees if one will match what we're looking for. Returns * 1 to it if so, and 0 if not; in the case 1 is returned the *lh will be * populated with details of the located handler. Since upon inlining, the * dynamic scope becomes lexical so far as the optimized bytecode is * concerned, then this just needs a scan of the table without any further * checks being needed. */ static MVMint32 search_frame_handlers_dyn(MVMThreadContext *tc, MVMFrame *f, MVMuint32 cat, MVMObject *payload, LocatedHandler *lh) { MVMuint32 i; if (f->spesh_cand && f->spesh_cand->jitcode && f->jit_entry_label) { MVMJitCode *jitcode = f->spesh_cand->jitcode; void *current_position = MVM_jit_code_get_current_position(tc, jitcode, f); MVMJitHandler *jhs = f->spesh_cand->jitcode->handlers; MVMFrameHandler *fhs = MVM_frame_effective_handlers(f); for (i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, 0); i < jitcode->num_handlers; i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, i+1)) { if (handler_can_handle(f, &fhs[i], cat, payload) && !in_handler_stack(tc, &fhs[i], f)) { lh->handler = &fhs[i]; lh->jit_handler = &jhs[i]; return 1; } } } else { MVMint32 num_handlers = f->spesh_cand ? f->spesh_cand->num_handlers : f->static_info->body.num_handlers; MVMint32 pc; if (f == tc->cur_frame) pc = (MVMuint32)(*tc->interp_cur_op - *tc->interp_bytecode_start); else pc = (MVMuint32)(f->return_address - MVM_frame_effective_bytecode(f)); for (i = 0; i < num_handlers; i++) { MVMFrameHandler *fh = &(MVM_frame_effective_handlers(f)[i]); if (!handler_can_handle(f, fh, cat, payload)) continue; if (pc >= fh->start_offset && pc <= fh->end_offset && !in_handler_stack(tc, fh, f)) { lh->handler = fh; return 1; } } } return 0; }
/* Looks for lexically applicable handlers in the current frame, accounting * for any inlines. The skip_first_inlinee flag indicates that we should skip * looking until we have encountered an inline boundary indicator saying that * we have crossed from an inlinee to its inliner's handlers; this is used to * handle the THROW_LEX_CALLER mode. If we never encounter an inline boundary * when skip_first_inlinee is true then we'll always return 0. * * If skip_first_inlinee is false or we already saw an inline boundary, then * we start looking for a matching handler. If one is found before seeing * another inline boundary, then it is applicable; the data pointed to by lh * will be updated with the frame handler details and 1 will be returned. * * Upon reaching an (or, in the case of skip_first_inlinee, a second) inline * boundary indicator, there are two cases that apply. We take the inline * that we are leaving, and look up the code ref using the code_ref_reg in * the inline. We know that we can never inline a frame that was closed over * (due to capturelex or takeclosure being marked :noinline). Thus, either: * 1. The outer of the inlinee is actually the current frame f. In this case, * we skip all inlined handlers and just consider those of f itself. * 2. The next frame we should search in is the ->outer of the inlinee, and * thus all the rest of the handlers in this frame should be ignored. In * this case, the MVMFrame **next_outer will be populated with a pointer * to that frame. * * The skip_all_inlinees flag is set once we are below the frame on the stack * to where the search started. Again, this is because a frame that did a * lexical capture may not be inlined, so we only need to consider the topmost * frame's handlers, not anything it might have inlined into it. */ static MVMint32 search_frame_handlers_lex(MVMThreadContext *tc, MVMFrame *f, MVMuint32 cat, MVMObject *payload, LocatedHandler *lh, MVMuint32 *skip_first_inlinee, MVMuint32 skip_all_inlinees, MVMFrame **next_outer) { MVMuint32 i; MVMuint32 skipping = *skip_first_inlinee; MVMFrameHandler *fhs = MVM_frame_effective_handlers(f); if (f->spesh_cand && f->spesh_cand->jitcode && f->jit_entry_label) { MVMJitCode *jitcode = f->spesh_cand->jitcode; void *current_position = MVM_jit_code_get_current_position(tc, jitcode, f); MVMJitHandler *jhs = jitcode->handlers; for (i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, 0); i < jitcode->num_handlers; i = MVM_jit_code_get_active_handlers(tc, jitcode, current_position, i+1)) { MVMFrameHandler *fh = &(fhs[i]); if (skip_all_inlinees && fh->inlinee >= 0) continue; if (fh->category_mask == MVM_EX_INLINE_BOUNDARY) { if (skipping) { skipping = 0; *skip_first_inlinee = 0; } else { MVMuint16 cr_reg = f->spesh_cand->inlines[fh->inlinee].code_ref_reg; MVMFrame *inline_outer = ((MVMCode *)f->work[cr_reg].o)->body.outer; if (inline_outer == f) { skip_all_inlinees = 1; } else { *next_outer = inline_outer; return 0; } } } if (skipping || !handler_can_handle(f, fh, cat, payload)) continue; if (!in_handler_stack(tc, fh, f)) { if (skipping && f->static_info->body.is_thunk) return 0; lh->handler = fh; lh->jit_handler = &jhs[i]; return 1; } } } else { MVMint32 num_handlers = f->spesh_cand ? f->spesh_cand->num_handlers : f->static_info->body.num_handlers; MVMint32 pc; if (f == tc->cur_frame) pc = (MVMuint32)(*tc->interp_cur_op - *tc->interp_bytecode_start); else pc = (MVMuint32)(f->return_address - MVM_frame_effective_bytecode(f)); for (i = 0; i < num_handlers; i++) { MVMFrameHandler *fh = &(fhs[i]); if (skip_all_inlinees && fh->inlinee >= 0) continue; if (fh->category_mask == MVM_EX_INLINE_BOUNDARY) { if (pc >= fh->start_offset && pc <= fh->end_offset) { if (skipping) { skipping = 0; *skip_first_inlinee = 0; } else { MVMuint16 cr_reg = f->spesh_cand->inlines[fh->inlinee].code_ref_reg; MVMFrame *inline_outer = ((MVMCode *)f->work[cr_reg].o)->body.outer; if (inline_outer == f) { skip_all_inlinees = 1; } else { *next_outer = inline_outer; return 0; } } } continue; } if (skipping || !handler_can_handle(f, fh, cat, payload)) continue; if (pc >= fh->start_offset && pc <= fh->end_offset && !in_handler_stack(tc, fh, f)) { if (skipping && f->static_info->body.is_thunk) return 0; lh->handler = fh; return 1; } } } return 0; }